How does this array with this indexing work? K&R exercise

Viewed 91

I am reading K&R, currently on chapter 1. After reading a section and trying to solve the problems, I like to check out for other solutions online just see different methods to tackle the same problem.

Exercise 1-14 says that we need to print an histogram of the frequencies of different characters in its input. This solution I found only takes into consideration alphabet characters:

#include <stdio.h>

#define MAX 122
#define MIN 97
#define DIFF 32

int main(){
  int c = EOF;
  int i, j;
  int array[MAX - MIN];
  printf("%d  ", MAX - MIN);

  for (i = MIN; i <= MAX; i++){
    array[i] = 0;
    printf("%d  ", i);
  }

  while ((c = getchar()) != EOF){
    if (c >= MIN)
    ++array[c];
    else {
      ++array[c + DIFF];
    }
  }

  for (i = MIN; i <= MAX; i++){
    printf("|%c%c|", i - DIFF, i);
    for (j = 1; j <= array[i]; j++){
      putchar('*');
    }
    putchar('\n');
  }

  return 0;
}

While I understand the logic behind this code, I don't understand how or why the array[] array works. When declaring the array, the size of it is 25 (MAX - MIN). This array should be indexed from 0 to 24. However during the first loop, the array is indexed using values from 97 to 122. But how is it possible to access the array if the indexing starts from a value much larger? Shouldn't the loop be

for (i = 0, i < MAX - MIN; i++)

It makes no sense to me how the array could be indexed from

array[97] ... array[122]

EDIT:

I added printf("%d ", MAX - MIN); and printf("%d ", i); in the first loop myself to try to see if it in fact was indexing the array from 97 onwards.

3 Answers
int array[MAX - MIN];

Here, size of array is 25 because 197-97 = 25.

 for (i = MIN; i <= MAX; i++){
    array[i] = 0;

Here, index of array[i] is out of bound because size of array is 25 and value and MIN is 97.

Also, ++array[c]; and j <= array[i]; is undefined because out of bound.

GCC compiler generated warning:

source_file.c: In function ‘main’:
source_file.c:14:10: warning: array subscript is above array bounds [-Warray-bounds]
     array[i] = 0;
          ^
source_file.c:20:12: warning: array subscript is above array bounds [-Warray-bounds]
     ++array[c];
            ^
source_file.c:20:12: warning: array subscript is above array bounds [-Warray-bounds]
source_file.c:28:27: warning: array subscript is above array bounds [-Warray-bounds]
     for (j = 1; j <= array[i]; j++){
                           ^

C11 J.2 Undefined behavior

  • Addition or subtraction of a pointer into, or just beyond, an array object and an integer type produces a result that points just beyond the array object and is used as the operand of a unary *operator that is evaluated (6.5.6).

  • An array subscript is out of range, even if an object is apparently accessible with the given subscript (as in the lvalue expression a[1][7] given the declaration int a[4][5]) (6.5.6).

Indeed the for loop is accessing the array out of bounds, invoking Undefined Behavior, which means that your program may crash or not.

MAX - MIN gives 25 and you access the array with indices in [97, 122], which is definetely wrong.

Similarly, ++array[c] and for (j = 1; j <= array[i]; j++) invoke Undefined Behavior as well, since they go out of bounds too.

PS: You need to declare your array with a size of MAX - MIN + 1, since the english alphabet has 26 letters.

There is no boundary checking in C for arrays, it is the responsibility of the programmer to take care of it.

so when you declare an array as

int array[ MAX - MIN ] ;

you are not restricted to use only sizeof( int ) * (MAX - MIN) but then if you don't use within this range behavior is quite erratic.

there are other programming languages that do enforce array boundary check but not c, unless of course it goes through rigorous compilation steps including string warning checks.

so in this case even though the program works it is not correct.

perhaps the bottom line to understand is

"Working code may not always be a correct code"

Related