2

I was practicing C programming and trying to create a 2D array with fixed rows, but variable columns. So, I used "array of pointers" concept i.e. I created an array such as int* b[4].

This is the code which was written:

#include <stdio.h>

int main(void) {

int* b[4];

int c[]={1,2,3};
int d[]={4,5,6,7,8, 9};
int e[]={10};
int f[]={11, 12, 13};

b[0]=c;
b[1]=d;
b[2]=e;
b[3]=f;

//printing b[0][0] to b[0][2] i.e. c[0] to c[2]
printf("b[0][0]= %d\tb[0][1]=%d\tb[0][2]=%d\n", b[0][0], b[0][1], b[0][2]); 

//printing b[1][0] to b[1][5] i.e. d[0] to d[5]
printf("b[1][0]= %d\tb[1][1]=%d\tb[1][2]=%d\tb[1][3]=%d\tb[1][4]=%d\tb[1][5]=%d\n", b[1][0], b[1][1], b[1][2], b[1][3], b[1][4], b[1][5]);

//printing b[2][0] i.e. e[0]
printf("b[2][0]= %d\n", b[2][0]); 

//printing b[3][0] to b[3][2] i.e. f[0] to f[2]
printf("b[3][0]= %d\tb[3][1]=%d\tb[3][2]=%d\n", b[3][0], b[3][1], b[3][2]); 

return 0;

}

and the output was as expected:

b[0][0]= 1  b[0][1]=2   b[0][2]=3
b[1][0]= 4  b[1][1]=5   b[1][2]=6   b[1][3]=7   b[1][4]=8   b[1][5]=9
b[2][0]= 10
b[3][0]= 11 b[3][1]=12  b[3][2]=13

So, I think memory has been allocated this way: enter image description here But, question chimes in when this code is executed:

#include <stdio.h>

int main(void) {

int* b[4];

int c[]={1,2,3};
int d[]={4,5,6,7,8, 9};
int e[]={10};
int f[]={11, 12, 13};

b[0]=c;
b[1]=d;
b[2]=e;
b[3]=f;

int i, j;
for (i=0; i<4; i++)
{
    for (j=0; j<7; j++)
    {
        printf("b[%d][%d]= %d ", i, j, b[i][j]);
    }
    printf("\n");
}



return 0;

}

And the output is something unusual:

 b[0][0]= 1 b[0][1]= 2 b[0][2]= 3 b[0][3]= 11 b[0][4]= 12 b[0][5]= 13 b[0][6]= -1079668976 
b[1][0]= 4 b[1][1]= 5 b[1][2]= 6 b[1][3]= 7 b[1][4]= 8 b[1][5]= 9 b[1][6]= -1216782128 
b[2][0]= 10 b[2][1]= 1 b[2][2]= 2 b[2][3]= 3 b[2][4]= 11 b[2][5]= 12 b[2][6]= 13 
b[3][0]= 11 b[3][1]= 12 b[3][2]= 13 b[3][3]= -1079668976 b[3][4]= -1079668936 b[3][5]= -1079668980 b[3][6]= -1079668964 

One can observe that b[0][i] continues seeking values from b[3][i], array b[2][i] continues seeking values from b[0][i] followed by a[3][i], array b[3][i] and b1[i] terminate.

Every time when this program is executed, the same pattern is followed. So, is there something more on the way memory is allocated, or is this a mere co-incidence?

3
  • 1
    you are accessing locations in memory which are out of bounds of your array, whatever is stored in those locations, garbage in other words, is getting printed. Commented Oct 29, 2014 at 6:12
  • When you assign b[0]=c;, what is it you think is being stored in b[0]? If you try to iterate j > 2 what happens? You must have some way of not attempting to read beyond the ends of space allocated for c, d, e & f. Since they differ in size, you either have to specifically limit your iteration to the appropriate size of each, or have some other way of signifying the end of data. Commented Oct 29, 2014 at 6:21
  • Compile with all warnings & debug info (gcc -Wall -Wextra -g). Then use the debugger (gdb). Beware of undefined behavior Commented Oct 29, 2014 at 6:22

4 Answers 4

2

As Hrishi notes in comments, the reason this is happening is that you're trying to access beyond the end of your arrays. So what's actually happening?

The short version is that you're reading past the end of your arrays, and reading into the next array (Or into unallocated memory). But why is this happening?

A brief aside on C-style arrays

In C, arrays are just pointers1. b is a pointer to the start of the array, so *b will return the first element of the array (Which in this case is a pointer to the start of b[0].

The syntax b[i] is just syntactic sugar; it's the same as *(b + i), which is doing pointer arithmetic. It's literally saying: "The memory address i places after b; tell me what's pointing there"2.

So if we look at, for example, b[0][3], we can translate that into *((*b) + 3): you're getting the address of the start of b, and then getting whatever is stored three memory address away from that.

So what's happening to you?

As it happens, your computer has stored b[3] starting at that address. That's what this is really telling you: where your computer is placing each sub-array in memory. This is because arrays are always laid out contiguously, one position right after another in memory (That's how the pointer arithmetic trick works). But because you defined c, d, e, and f individually, the memory manager did not allocate them contiguous to one another, but instead just put them wherever it wanted. The resulting pattern is just what it came up with. As best I can tell, your arrays are laid out in memory like this:

--------
| e[0] |
--------
| c[0] |
--------
| c[1] |
--------
| c[2] |
--------
| f[0] |
--------
| f[1] |
--------
| f[2] |
--------

d is located somewhere in memory as well, but it could be before or after this contiguous block; we don't know.

However you can't rely on this. As I mention in a footnote, the ordering of allocated memory is not defined by the language, so it could (And does) change depending on any number of factors. Run this same code tomorrow, and it probably won't be exactly the same.

The next obvious question is: "What about b[0][6]? Why is that such a weird number?"

The answer is that you've run out of array, and you're now trying to read from unallocated memory.

When your program gets run, the operating system gives it a certain chunk of memory and says "Here, do with that whatever you like." When you declare a local variable on the stack (As you have here) or on the heap (With malloc), the memory manager grabs some of that memory and gives it back to you4. All the memory you're not currently using is still there, but you have no idea what is stored there; it's just leftover data from whatever was last using that particular chunk of memory. Reading this is also undefined behaviour in C, because you obviously have no control over what is stored in that memory.

I should note that most other languages (Java, for instance) wouldn't allow you to do anything like this; it would throw an exception because you're trying to access beyond the bounds of an array. C, however, isn't that smart. C likes to give you enough rope to hang yourself, so you need to do your own bounds checking.


1 This is a simplification. The truth is slightly more complicated
2 This implementation is why array indices start at 0.
3 This is an example of undefined behaviour, which is Very Bad. Basically it means that this result isn't consistent. It's happening the same way every time, on your computer, right now. Try it on a friend's computer, or even on your computer an hour from now, and you might get something completely different.
4 This is another oversimplification, but for your purposes it's close enough to true

Sign up to request clarification or add additional context in comments.

Comments

2

Your little drawing is right, the only thing is that since you sequentially declared the arrays in your function, they're all in the stack, side by side. So, by accessing beyond your arrays' limits you're accessing the next array.

Comments

2

Compile with all warnings & debug info (gcc -Wall -Wextra -g). Then use the debugger (gdb). Beware of undefined behavior (UB).

Your b[2] is e which is an array of one element. At some time you are accessing b[2][3]. This is a buffer overflow (an instance of UB). What really happens is implementation specific (can vary with the compiler, its version, the ABI, the processor, the kernel, the moon, the compiler flags, ...) You may want to study the assembled code to understand more (gcc -fverbose-asm -S).

BTW, you should not suppose that arrays c, d, e, f have some particular memory layout.

Comments

0

When you print the values of the array elements using the specific location addresses you get the exact array values . but when you execute the same program you get garbage values as in c language we have no bond checking in C.Thus when you try accessing the value of a location that is beyond the memory scope utilized by you all you get is the data stored on that memory which is also referred as garbage value . So to get proper result you need to keep a check that accesses the values that are in array bond or say in the limit defined for that array.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.