Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Incrementing the array pointer beyond the last item

Tags:

arrays

c

pointers

I was having a little fun with C Programming and array pointers.

Can someone explain what is happening when I advance an array pointer beyond the size of the array?

It looks like I'm accessing the memory cell that is directly after the array, but I just want to be sure.

  1. Do these numbers mean anything?
  2. Why is the last number a zero?
  3. Should a program be able to access memory it hasn't allocated?

So many questions!

int arr[] = { 1, 2, 3, 4, 5 };
int *xPtr = arr;

for(int i = 0; i < 10; i++) {
    printf("current pointer is %d\n", *xPtr++);
}

Results in:

current pointer is 1
current pointer is 2
current pointer is 3
current pointer is 4
current pointer is 5
current pointer is 0
current pointer is 127926431
current pointer is -759946469
current pointer is -492049712
current pointer is 32766

This was the only way I found to properly iterate through the array. Is this correct?

int arraySize = sizeof(arr) / sizeof(int);
for(int i = 0; i < arraySize; i++) {
    printf("current pointer is %d\n", *xPtr++);
}

Results in:

current pointer is 1
current pointer is 2
current pointer is 3
current pointer is 4
current pointer is 5
like image 941
Marty Miller Avatar asked Aug 05 '19 05:08

Marty Miller


3 Answers

You are accessing memory outside the array. Array has just 5 elements, and you increase the pointer beyond that, and dereference it. There are actually two kinds of bad things here: you are dereferencing outside the array, but you are also increasing the pointer more than one step beyond end of the array. Neither is allowed.

This is undefined behaviour, so anything could happen. In this case it looks like you are simply getting the memory contents after the array, interpreted as ints. In the context of your C program, they're just garbage values, because once you have undefined behaviour in C, all bets are off, the program could have crashed or worse.

If you want to make sense of a program which has UB, you gotta compile it, then look at the assembly code of that particular compilation. Just note that next time you compile it, result could be different (compiler switches, compiler or library updates, different computer...), and the new assembly code could have totally different behaviour (because the C code had UB). Generally this is not useful, UB is UB and it rarely makes sense to try and reason about what it does.


C has no array bounds checking, so C compiler does not perform any checks. In a modern PC operating system with memory protection, the OS will kill the program if you try to access memory that is not given to it, but it has coarse resolution (for example 4 KB pages), and there might be a lot of memory belonging to your program anyway, so OS might not notice anything bad for megabytes after the array.


2nd version looks good. Just remember that sizeof works like that only for actual arrays, not for pointers, and not for array parameters of functions (because those are actually pointers, not arrays, despite the syntax).

like image 103
hyde Avatar answered Oct 21 '22 16:10

hyde


You need to understand pointer increment *xPtr++ works by incrementing the size of the object it is pointing to. In your case being an int, every operation does an increment of the sizeof(int) depending on the size of int in your system.

Since your array has only 5 elements, on a machine with a 4 byte int, you cannot increment it more than 5 counts. Beyond that you are accessing memory that is not allocated for the array and accessing the value from those locations invokes undefined behavior.

Your second approach seems right, with a simple fix use the return type of sizeof() from int to size_t although an implicit conversion happens on assignment

size_t arraySize = sizeof(arr) / sizeof(int);
for(size_t i = 0; i < arraySize; i++) {
    printf("current pointer %p and value is %d\n", (void*)xPtr, *xPtr++);
}
like image 35
Inian Avatar answered Oct 21 '22 15:10

Inian


C does not check for Array Bounds. So even if you access an array beyond it's size which is declared, it will not give any error. The answers to your questions, according to me :

  1. No the numbers are purely garbage value.
  2. The last number can be anything (garbage including zero). As per ISO C standard it is called Undefined Behavior.
  3. No it shouldn't! But C is a language of the time when compilers were slow and even saving 3-4 instructions in Assembly meant a lot!
like image 22
0ne0rZer0 Avatar answered Oct 21 '22 15:10

0ne0rZer0