2

I'm having a problem using an unsigned char as an iterator. Using the following code results in being stuck inside a FOR loop. The output looks like this.

unsigned char i;
char * arr;
int * freq;
arr = (char *)(malloc(256*sizeof(char)));
freq = (int *)(malloc(256*sizeof(int)));
for (i=0; i<=255;i++){
    arr[i]=i;
    freq[i]=0;
    printf("%c",i);
}

My question is why this happens? Is it due to using an unsigned char as an iterator?

  • 5
    Since `unsigned char i` cannot hold a value greater than 255. `i<=255` is always true. – chux - Reinstate Monica Jan 28 '16 at 15:19
  • Don't cast the result of `malloc` & friends in C! And `sizefo(char)` is _defined_ to yield `1`. There is no use in explicitly writing it. – too honest for this site Jan 28 '16 at 15:20
  • Also, using a char as an iterator is not likely to be more "efficient" you may as well use an integer. I could be wrong though –  Jan 28 '16 at 15:21
  • @aidan.plenert.macdonald: The correct type for an interator on an array would be `size_t` (which is unsigned). Alternatively `unsigned int` can be used, if the values are guaranteed to be `<= SIZE_MAX`. – too honest for this site Jan 28 '16 at 15:23
  • 1
    @chux: `255` is the minum maximum(!) value required by the standard. There is no statment an `unsigned char` can not hold larger values. – too honest for this site Jan 28 '16 at 15:24
  • @Olaf Its hard to say what is "correct". It depends on the purpose. In terms of efficiency, there is debate in the comments of the answers http://stackoverflow.com/questions/34860918/gcc-hinting-at-vectorization/34920949#34920949 –  Jan 29 '16 at 01:30
  • @aidan.plenert.macdonald: `sizeof` yields a `size_t`. That is in units of `char`s, which is guaranteed to be the smalles possible array-element, Thus `size_t` guarantees correct indxing of an array **under all circumstances** and for all types. An `int` may not provide that, e.g. for typical 32 bit systems with both types having 32 bits, if >2GiB address space is available. – too honest for this site Jan 29 '16 at 01:42

4 Answers4

9
i <= 255

If i is of type unsigned char and that type is 8 bit on your platform (which it likely is), then the expression will always be true and you have an infinite loop. It is well-defined behavior, though. The unsigned char will simply wrap around and its value will start at 0 again once it has reached 255.

The solution is simple of course: change the type of i to int.

To avoid such surprises in the future, make sure to turn on your compiler's warnings. If I compile the bogus loop with GCC and pass it the -Wall and -Wextra flags, it will tell me this.

main.c: In function ‘main’:
main.c:5:17: warning: comparison is always true due to limited range of data type [-Wtype-limits]
   for (i = 0; i <= 255; ++i)
                 ^
5gon12eder
  • 24,280
  • 5
  • 45
  • 92
1

Primary issue: Since unsigned char i cannot hold a value greater than UCHAR_MAX. i<=255 is always true. UCHAR_MAX is commonly 255, as it certainly is on OP's platform, but may be more.

Other notes:

When using an array index, best to use size_t.

Casting malloc() results is not needed. Also consider multiple by the size of the variable and not the size of the type. - IMO: easier to maintain and code correctly.

Avoid magic numbers 256, 255 floating about.

#define N 256
size_t i;
char * arr;
int * freq;
arr = malloc(sizeof *arr * N);
freq = malloc(sizeof *freq * N);
for (i=0; i<N;i++){
    arr[i]=i;
    freq[i]=0;
    printf("%c",i);
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
0

Because your condition is i <= 255, when i becomes 255, it will be incremented by one. The maximum range of an unsigned char at your machine is [0,255], so it just wrap around to zero again. So the loop, continues for ever.

This issue is known as arithmetic or integer overflow

Manos
  • 2,136
  • 17
  • 28
  • I would write "The maximum range of an unsigned char is [0,255] **[on your machine]**" instead. Emphasis added. `unsigned char` is **at least** 8 bits, not at most. – cadaniluk Jan 28 '16 at 15:24
0

A for loop does the following: It performs the initialisation. Then it checks the loop condition. If the loop condition is true, it performs the loop, then the increment expression. And then it checks the loop condition again. This is literally what it does.

When i = 255, and i++ is executed, the compiler tries to set i to 256, but because it is an unsigned char and likely 8 bit, that 256 is truncated to zero. And then the loop condition i <= 255 is again true. The compiler follows exactly what you told it to do, not what you wanted it to do.

gnasher729
  • 51,477
  • 5
  • 75
  • 98