4

I'm working on a lab assignment for a C programming class I'm taking. I wrote the code in my local Cygwin directory, compiled it with gcc, and the executable that is produced works exactly the way I want it to without any errors.

When I copy my code over to my school's UNIX server and compile it with gcc, I don't get any errors, but when I try to run it, nothing happens.

I tried doing gcc 2darray.c -Wall -pedantic and this is what was returned:

2darray.c: In function 'main':
2darray.c:5:3: warning: missing braces around initializer [-Wmissing-braces]
2darray.c:5:3: warning: (near initialization for 'M[0]') [-Wmissing-braces]
2darray.c:5:24: warning: C++ style comments are not allowed in ISO C90 [enabled by default]
2darray.c:5:24: warning: (this will be reported only once per input file) [enabled by default]

The errors mention something about initializing the array M, but I don't see any problems with the way I initialized it. Here's the code I'm trying to compile:

#include <stdio.h>

int main(void)
{
  int M[10][10] = {0}; // creating a 10x10 array and initializing it to 0
  int i, j; // loop variables
  int sum[10] = {0}; // creating an array to hold the sums of each column of 2d array M

  for (i = 1; i < 10; i++) // assigning values to array M as specified in directions
    {
      for (j = i - 1; j < i; j++)
        {
          M[i][j] = -i;
          M[i][j+1] = i;
          M[i][j+2] = -i;
        }
    }

  for (i = 0; i < 10; i++) // printing array M
    {
      for(j = 0; j < 10; j++)
        {
          printf("%3d", M[i][j]);
        }
      printf("\n");
    }

  printf("\n");
  for (i = 0; i < 10; i++) // calculating sum of each column
    {
      for (j = 0; j < 10; j++)
        {
          sum[i] = M[j][i] + sum[i];
        }
      printf("%3d", sum[i]);  // printing array sum
    }

  return 0;
}

I tried inserting a printf statement between the variable declarations and the first for loop and the statement printed, so maybe something goes wrong in my loops?

If relevant, here's what the output looks like from my Cygwin directory and what it should like in my school's UNIX directory:

  0  0  0  0  0  0  0  0  0  0
 -1  1 -1  0  0  0  0  0  0  0
  0 -2  2 -2  0  0  0  0  0  0
  0  0 -3  3 -3  0  0  0  0  0
  0  0  0 -4  4 -4  0  0  0  0
  0  0  0  0 -5  5 -5  0  0  0
  0  0  0  0  0 -6  6 -6  0  0
  0  0  0  0  0  0 -7  7 -7  0
  0  0  0  0  0  0  0 -8  8 -8
  0  0  0  0  0  0  0  0 -9  9

 -1 -1 -2 -3 -4 -5 -6 -7 -8  1
suhh_drude
  • 63
  • 4

2 Answers2

7

You're accessing a row of the array M outside its bounds, causing undefined behavior.

for (i = 1; i < 10; i++) 
// i ranges from 1 to 9
  {
    for (j = i - 1; j < i; j++)
    // j ranges from i-1 (0 when i==1) to i-1 (8 when i==9)
    // Consider what happens when j==8
      {
        M[i][j] = -i;       // j == 8
        M[i][j+1] = i;      // j == 9
        M[i][j+2] = -i;     // j == 10, out of bounds
      }
  }

When I looked at your code, the j+2 index struck me as the most likely place for an out-of-bounds access. I copied your program and added a line:

      M[i][j] = -i;
      M[i][j+1] = i;
      if (j+2 >= 10) puts("OUT OF RANGE");
      M[i][j+2] = -i;

When I ran the program, it printed OUT OF RANGE.

As for the warnings you get from gcc -Wall -pedantic, they're not really a problem. The warning about the // comments can be avoided by compiling with -std=c99. The "missing braces" warning is spurious. Nested braces in initializers for nested data structures are optional, and {0} is a perfectly valid idiom for initializing an entire data structure (array, struct, union) to zero. Recent versions of gcc (5.2.0 in particular) don't warn about it.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • Good, but the problem is one step earlier. The second index of M can go as high as 9, so when `j` is 9, the line with `j+1` is a problem. – donjuedo Nov 01 '15 at 19:39
  • Not true I think. 9 is within the range, isn't it? – Ely Nov 01 '15 at 19:41
  • 1
    @donjuedo `j < i` and `i < 10`, so the maximum value for `j` is 8. – user3386109 Nov 01 '15 at 19:42
  • Thanks for your help, Keith. I added an `if (j+2 > 9) break;` statement before the third expression in my first nested `for` loop and it worked. – suhh_drude Nov 01 '15 at 19:58
  • @user10721: Adding a `break` avoids the undefined behavior; I don't know whether it's the best solution. That depends on what the program is *supposed* to do, and you haven't give us the requirements. – Keith Thompson Nov 01 '15 at 20:35
  • @MarcGlisse: That option doesn't exist in gcc 4.8.4. It does exist in 5.2.0, but the generated code depends on `libubsan.so.0`, which I don't have. – Keith Thompson Nov 01 '15 at 21:39
2

Recent versions of clang and gcc come with a tool that trivializes such questions. Please always use it, it will save you a lot of time looking for errors.

$ gcc s.c -Wall -Wextra -fsanitize=undefined
$ ./a.out
s.c:15:15: runtime error: index 10 out of bounds for type 'int [10]'
s.c:15:21: runtime error: store to address 0x7fff6c53f2c0 with insufficient space for an object of type 'int'
0x7fff6c53f2c0: note: pointer points here
 09 00 00 00  e5 ef 74 8a 11 7f 00 00  08 00 00 00 09 00 00 00  b0 10 40 00 00 00 00 00  00 00 00 00
              ^

Apparently, cygwin might not support libubsan yet, so you may need -fsanitize-undefined-trap-on-error which replaces the nice error message with a simple trap, which you can then investigate with gdb. Yes, a debugger is another tool and will require a bit of time to learn, but not that much, and it will save you more time looking for bugs.

Marc Glisse
  • 7,550
  • 2
  • 30
  • 53