Loop starting at -1 doesn't print anything

CLoopsIntegerSizeofNegative Number

C Problem Overview


This program is supposed to print out the elements of array, but when it is run, no output is shown.

#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 doesn't this program show any output?

C Solutions


Solution 1 - C

sizeof returns an unsigned integer, so TOTAL_ELEMENTS is also unsigned.

d is signed. Initially, d is -1. However, when doing the comparison, d is implicitly typecast to unsigned, so it is no longer -1 when being compared to TOTAL_ELEMENTS, it is actually UINT_MAX (which is 4294967295 on my machine, but might differ for others).

Also,

If you want to fix this, typecast TOTAL_ELEMENTS to int:

for(d = -1; d <= (int)(TOTAL_ELEMENTS - 2); d++) 

This will print:

23
34
12
17
204
99
16

As you'd expect. You may also want to look at https://stackoverflow.com/questions/2084949/comparison-operation-on-unsigned-and-signed-integers for more information on the topic of signed-unsigned comparisons.

It is worth noting that turning on compiler warnings would've helped you figure out what was going on (as observed by hyde in his comment):

$ gcc -Wall -Wextra test.c
test.c:7:17: warning: comparison of integers of different signs: 'int' and 'unsigned long' [-Wsign-compare]
      for(d = 0; d < TOTAL_ELEMENTS; d++) 
              ~ ^ ~~~~~~~~~~~~~~
1 warning generated.

Alternatively, why not start d at 0 and run to TOTAL_ELEMENTS - 1 instead? You can even drop the typecast, that is necessary only for the corner case of d = -1.

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

As a footnote, here are the relevant C99 Standard excerpts:

  1. 6.3.1.8p2 defines the conversion from signed to unsigned type.

    > If the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then > the operand with signed integer type is converted to the type of the > operand with unsigned integer type.

  2. 6.3.1.3p2 defines how the conversion is done: By adding UINT_MAX + 1 to the signed representation.

    > If the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value > that can be represented in the new type until the value is in the > range of the new type.

    So -1 => -1 + (UINT_MAX + 1) = UINT_MAX, for this scenario.

Solution 2 - C

My gcc outputs this warning:

warning: comparison of integers of different signs: 'int' and 'unsigned long' [-Wsign-compare]
      for(d = 0; d < TOTAL_ELEMENTS; d++) 

which means that (TOTAL_ELEMENTS-2) is unsigned int while d is signed int. This makes the expression always false for the initial value of d, since (unsigned int)(-1) > (TOTAL_ELEMENTS-2).

Solution 3 - C

Binary operations between different integral types are performed within a "common" type defined by so called usual arithmetic conversions. So int d is of singed type initialized with value -1. Which when convert into unsigned int it will return maximum of unsigned int which is much much greater than the value returned by TOTAL_ELEMENTS.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionrohit kumarView Question on Stackoverflow
Solution 1 - Ccs95View Answer on Stackoverflow
Solution 2 - CCIsForCookiesView Answer on Stackoverflow
Solution 3 - CPattView Answer on Stackoverflow