This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Confused about C macro expansion and integer arithmetic
A riddle (in C)
The output of the following C program is to print the elements in the array. But when actually run, it doesn't do so.
#include<stdio.h>
#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))
int array[] = {23,34,12,17,204,99,16};
int main()
{
int d;
for(d=-1;d <= (TOTAL_ELEMENTS-2);d++)
printf("%d\n",array[d+1]);
return 0;
}
Why is that?
sizeof() returns unsigned int and so in the <= comparison, d gets converted to unsigned int. -1 when converted to unsigned int is 0xffffff. Since 0xffffff > (7-2), for-loop body won't be executed even once.
This fails because sizeof is returning a value of type size_t, which is unsigned. This causes the comparison to promote the -1 to unsigned, which is generally a very large value and thus make the comparison fail.
You should receive warnings for the sign mismatch.
The point is the type of value sizeof returns.
It's a size_t, which is an unsigned type, so converting -1 to that type for the comparison produces the maximal value of the type, which is far larger than 5.
for(d=-1;d <= ((int)TOTAL_ELEMENTS-2);d++)
I guess this is more clear:
for(d = 0; d < TOTAL_ELEMENTS; d++)
printf("%d\n",array[d]);
And size_t case should not be a problem anymore.
Your original problem works, when I do the following:
#define TOTAL_ELEMENTS 7
int array[] = {23,34,12,17,204,99,16};
int main()
{
int d;
for(d=-1; d <= (TOTAL_ELEMENTS - 2); d++)
printf("%d\n",array[d+1]);
return 0;
}
This has something to do with comparing a negative number d=-1 with (TOTAL_ELEMENTS-2). I believe it might be sizeof, butI will leave finding out why as an exercise.
Leaving your original #define as it was --
#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))
-- but using zero-based indexing also worked.
I'm not sure why your original TOTAL_ELEMENTS definition caused the loop not to print.
A more standard way to write this loop which works would be
for(d = 0; d < TOTAL_ELEMENTS; d++)
...
as was pointed out by correctly by several others here already, the problem lies with signed/unsigned values being compared. This construct would have avoided the problem.
Related
Had been going through this code:
#include<cstdio>
#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))
int array[] = {1,2,3,4,5,6,7};
int main()
{
signed int d;
printf("Total Elements in the array are => %d\n",TOTAL_ELEMENTS);
for(d=-1;d <= (TOTAL_ELEMENTS-2);d++)
printf("%d\n",array[d+1]);
return 0;
}
Now obviously it does not get into the for loop.
Whats the reason?
The reason is that in C++ you're getting an implicit promotion. Even though d is declared as signed, when you compare it to (TOTAL_ELEMENTS-2) (which is unsigned due to sizeof), d gets promoted to unsigned. C++ has very specific rules which basically state that the unsigned value of d will then be the congruent unsigned value mod numeric_limits<unsigned>::max(). In this case, that comes out to the largest possible unsigned number which is clearly larger than the size of the array on the other side of the comparison.
Note that some compilers like g++ (with -Wall) can be told to warn about such comparisons so you can make sure that the code looks correct at compile time.
The program looks like it should throw a compile error. You're using "array" even before its definition. Switch the first two lines and it should be okay.
This question already has answers here:
size_t vs int in C++ and/or C
(9 answers)
Closed 4 years ago.
I have encountered a problem while I was using a loop like this,
//vector<int> sides;
for (int i = 0; i < sides.size()-2; i++) {
if (sides[i] < sides[i+1] + sides[i+2]) {
...
}
}
The problem was that the size() method uses an unsigned number. So, vectors of size less than 2 make an undefined outcome.
I understand that I should have used an unsigned variable for the loop but it doesn't solve the problem. So I had to deal with it by typecasting or using some conditions.
My question is that why do STL uses an unsigned int to eliminate negative index access violation and generating more problems?
It was decided that containers would use unsigned indexes and sizes way back in the 90s.
On the surface this seemed wise; I mean, sizes and indexes into containers cannot be negative. It also permits slightly larger max values, especially on 16 bit systems.
It is now considered a mistake; your code is but one of the many reasons why. std2 will almost certainly use ptrdiff_t, the signed partner of size_t, for sizes and indexes.
Note that 1u-2 is defined behaviour; it is -1 cast to unsigned, which is guaranteed to be the max unsigned value of that type.
You can fix your code in many ways, including:
for (int i = 0; i+2 < sides.size(); i++) {
if (sides[i] < sides[i+1] + sides[i+2]) {
or
for (int i = 0; i < (std::ptrdiff_t)sides.size()-2; i++) {
if (sides[i] < sides[i+1] + sides[i+2]) {
this second one can break on containers near the size of your memory space limit; on 64 bit systems this is not a problem, on 32 bit systems and vectors of char there is a slim chance you could create a vector large enough.
The reason is that the operator sizeof that determines the size of any object returns a value of the type size_t. So for example also the standard C functiuon strlen has return type size_t.
As result it is adopted that standard containers also returns their sizes as values of the type size_t.
As for the loop then it can be rewritten for example the following way
for ( size_t i = 0; i + 2 < sides.size(); i++) {
if (sides[i] < sides[i+1] + sides[i+2]) {
...
}
}
This question already has answers here:
Why does long long n = 2000*2000*2000*2000; overflow?
(6 answers)
Closed 1 year ago.
Why the below code gives integer overflow warning:
#include <stdio.h>
int main()
{
long long int x = 100000 * 99999;
return 0;
}
Whereas below code works perfectly:
#include <stdio.h>
int main()
{
long long int x = 100000000000000;
return 0;
}
Because here
long long int x = 100000 * 99999;
two ints are multiplied. Try
long long int x = 100000LL * 99999;
Make it 100000LL * 99999LL for the warning to go away.
You should read this or this.
The type of the integer literal is the first type in which the value
can fit, from the list of types which depends on which numeric base
and which integer-suffix was used.
(Thanks to #UnHolySheep who makes me notice it).
If you want the compiler to interpret differently your literal, you have to add a suffix. For example, with int, you can add LL or ll to specify that it's a long long int. With unsigned numbers the suffix is u.
With floating point literals, it's the same: there's a default type, which is double, but if you want a float you can easily use the f (or f) suffix. With floating point you can even use exponential rappresentation (usign the e).
This question already has answers here:
What's the best way to do a reverse 'for' loop with an unsigned index?
(20 answers)
Closed 7 years ago.
When I put the following in my program:
for (size_t i = VectorOfStructs.size()-1; i > 0; i--)
It works correctly but does "i" will never equal 0.
So, I cannot access the first element (VectorOfStructs[0]).
If I change it to:
for (size_t i = VectorOfStructs.size()-1; i > -1; i--)
The program doesn't even enter the for loop! But, if I change it to the following:
for (int i = VectorOfStructs.size()-1; i > -1; i--)
It works exactly as I want it to (Iterates through all the elements).
So, my questions are:
(A) Why does the 2nd code snippet fail to execute?
(B) Why does the 3rd code snippet execute accordingly while the 2nd doesn't?
Any insight would be greatly appreciated!
All loops go forward, even the ones that go backwards.
What you want is either this:
for (std::size_t i = 0, e = VectorOfStructs.size(); i != e; ++i)
{
std::size_t const ri = e - i - 1;
// use "VectorOfStructs[ri]"
}
Or better:
for (auto rit = VectorOfStructs.rbegin(); rit != VectorOfStructs.rend(); ++rit)
{
// use "*rit"
}
(Your second snippet fails because i is unsigned, so -1 is converted to the same type as i and becomes the maximal representable value, so the comparison is always true. By contrast, i is signed in the third snippet.)
The second example uses size_t as type for i, which is an unsigned type, thus it can never have negative values; this also means that it cannot be properly compared with -1
But (int)-1 is bit-represented as 0xFFFFFFFF, which represents a rather large number (2^32-1) for size_t. i>0xFFFFFFFF can never be true, since 0xFFFFFFF is the largest value a size_t can ever hold.
The 3rd example uses signed int (which allows for negative numbers and therefore the test succeeds).
This one should work:
for (size_t i = VectorOfStructs.size(); i-- > 0;) {
use(VectorOfStructs[i]);
}
In second one you comparing variable 'i' with -1 , and here it is of type size_t and size can not be in negative so it fails.
In third one , 'i' is integer type and integer has range from -32568 to +32567 (for int=2 byte in a system)
Overall size_t variable can not have negative values because a physical memory will have its existence in the system
Why does the 2nd code snippet fail to execute?
size_t is unsigned, so it is by definition never negative. So your loop condition is always true. The variable "wraps around" to the maximum value.
size_t is an unsigned type so -1 is the maximum value size_t can take. In the second snippet size_t can't be greater than this maximum value so the loop isn't entered.
On the other hand, int is a signed type so the comparison to -1 is as you expect.
Int and size_t are both integer types but int can hold negatives as well as positives.
int ranges from -2^31 -1 to 2^31 -1 while size_t ranges from 0 to 2^32 -1
Now, when you write something like int a = -1 it is indeed -1 but when you do so with size_t you get the max int 2^32 -1
So in the 2nd snippet no size_t value will ever exceed -1 as it really 2^32 -1
In the 3rd snippet the type compared is int and when int is compared to -1 it sees it as -1 so it executes the way you planned
When the compiler sees i > -1 and notices that the subexpressions i and -1 have different types, it converts them both to a common type. If the two types (std::size_t and int) have the same number of bits, which appears to be the case for your compiler, the common type is the unsigned one (std::size_t). So the expression turns out to be equivalent to i > (std::size_t)-1. But of course (std::size_t)-1 is the maximum possible value of a size_t, so the comparison is always false.
Most compilers have a warning about a comparison that is always true or always false for reasons like this.
Whenever you compare 'signed' and 'unsigned' the 'signed' values are converted to 'unsigned', first. That covers (#1) and (#2), having a problems with 'unsigned(0-1)' and 'some unsigned' > 'unsigned max'.
However, making it work by forcing a 'signed'/'signed' compare (#3), you loose 1/2 of the 'unsigned' range.
You may do:
for(size_t n = vector.size(); n; /* no -- here */ ) {
--n;
// vector[n];
}
Note: unsigned(-1) is on many systems the biggest unsigned integer value.
Had been going through this code:
#include<cstdio>
#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))
int array[] = {1,2,3,4,5,6,7};
int main()
{
signed int d;
printf("Total Elements in the array are => %d\n",TOTAL_ELEMENTS);
for(d=-1;d <= (TOTAL_ELEMENTS-2);d++)
printf("%d\n",array[d+1]);
return 0;
}
Now obviously it does not get into the for loop.
Whats the reason?
The reason is that in C++ you're getting an implicit promotion. Even though d is declared as signed, when you compare it to (TOTAL_ELEMENTS-2) (which is unsigned due to sizeof), d gets promoted to unsigned. C++ has very specific rules which basically state that the unsigned value of d will then be the congruent unsigned value mod numeric_limits<unsigned>::max(). In this case, that comes out to the largest possible unsigned number which is clearly larger than the size of the array on the other side of the comparison.
Note that some compilers like g++ (with -Wall) can be told to warn about such comparisons so you can make sure that the code looks correct at compile time.
The program looks like it should throw a compile error. You're using "array" even before its definition. Switch the first two lines and it should be okay.