tags:

views:

83

answers:

6

The expected output of the following C program is to print the array elements. 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;
}

What is the reason ?

+5  A: 

TOTAL_ELEMENTS is unsigned. -1, when converted to unsigned, is a really huge number, which is not less than 6. Thus, your loop never runs.

zvrba
Yep... you should never mix signed / unsigned assignments or comparison without a proper reason and in that case an explicit casting is in place. Also, most compilers should have issued a warning for this if the appropriate warning level was set.
smichak
+1  A: 

The reason is that the loop is never executed. This is because TOTAL_ELEMENTS returns a size_t, an unsigned type.

You can fix this by casting (TOTAL_ELEMENTS-2) to an int.

Frerich Raabe
A: 

You need to do the following:

for(d=0;d < TOTAL_ELEMENTS;d++)
    printf("%d\n",array[d]);

as sizeof(...) produces an unsigned value.

reece
+3  A: 

When you do the comparison d <= (TOTAL_ELEMENTS-2), a type conversion is performed. d is of type signed int while (TOTAL_ELEMENTS-2) is of type size_t, which is an unsigned type. The rules of C say that when an operator has a signed and an unsigned argument, and the unsigned argument is of greater or equal size to the signed argument, then the signed argument is converted to unsigned.

That is, the comparison ends up as:

(size_t) d <= (TOTAL_ELEMENTS-2)

And because size_t is unsigned, (size_t) -1 is a really, really large number, not -1 any more. For a 32-bit size_t it would be 232 - 1 = 4,294,967,295.

To fix this, you can explicitly cast the right-hand side to signed int:

d <= (int) (TOTAL_ELEMENTS-2)

Or, better, just get rid of the weird negative indexing and such.

For future reference, turn on all the compiler warnings you can. gcc, for instance, will print a warning if you turn on -Wall -Wextra:

$ gcc -o arrayprint -Wall -Wextra -ansi arrayprint.c 
arrayprint.c: In function ‘main’:
arrayprint.c:11: warning: comparison between signed and unsigned
John Kugelman
@John: other than casting the result of the macro to `int`, it would be much simpler to use `size_t` for `d` from the start and to use proper bounds `0` for the start and `d < TOTAL_ELEMENTS` for the condition.
Jens Gustedt
+3  A: 

At first, I didn't know. But when I compiled it using GCC, it was obviously apparent:

$ gcc -Wall -Wextra -Os a.c
a.c: In function `main':
a.c:11: warning: comparison between signed and unsigned

So you have a comparison as follows:

(int) -1 <= (size_t) 5

Since one of the types is signed and the other is unsigned, they first need to be converted to a common type. In this case, it is size_t. That makes it:

(size_t) -1 <= (size_t) 5

Now -1 cannot be represented in an unsigned type. Therefore, 2^32 (or however many bits size_t has) is added to it, which makes it 4294967295. So the comparison really is:

4294967295 <= 5

And that's false, therefore the loop body is never executed.

Roland Illig
A: 

Simply change

#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))

With

#define TOTAL_ELEMENTS (int)(sizeof(array)/sizeof(array[0]))-2
Cristy
@Cristy: you really take it at the wrong end. Array indices should always just be `size_t`. He just should change `d` to be of `size_t` and do a proper indexing and all the fuzz goes away...
Jens Gustedt