I am new to C and I currently have some troubles. Please have a look at the following Code:
int main (int argc, char *argv[]) {
int j = 2;
int i = 100;
int *pi = &i;
pi = &j; //those 2 lines should do nothing, in my opinion
pi = &i; //
pi[1] = -4;
printf("i = %d, j = %d, *pi = %d\n", i, j, *pi);
return EXIT_SUCCESS;
}
The code fails with a SegFault. Some investigation with gdb:
(gdb) print &j
$1 = (int *) 0x7fffffffde80
(gdb) print &i
$2 = (int *) 0x7fffffffde84
However, without the 2 lines, the code works fine, because i and j seem to swap places in the memory - but why??
(gdb) print &j
$1 = (int *) 0x7fffffffde84
(gdb) print &i
$2 = (int *) 0x7fffffffde80
I asked my teacher, but unfortunately she had no idea.
Thanks in advance!!
EDIT: by working fine, i mean the printf prints: i = 100, j = -4, *pi = 100 -- pi[1] points on j, seemingly
The question is, why do those 2 Lines change anything?
pi
is a pointer and you are making it point to a integer later when you do
pi[1] = -4;
You are accessing the memory which is not under your control or the memory not allocated by you so it leads to undefined behavior hence the seg fault.
Statement pi[1] = -4;
invoke undefined behavior. Anything could happen. You may get either expected or unexpected results.
pi[1] = -4;
is equivalent to *(pi+1) = -4;
. Pointer one past the object i
is allowed but dereferencing it will invoke undefined behavior.
7 For the purposes of these operators, a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.
8 If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined. If the result points one past the last element of the array object, it shall not be used as the operand of a unary * operator that is evaluated.
The question is, why do those 2 Lines change anything?
The answer is, its because of undefined behavior.
With my compiler it is as follows:
Of course pi[1]
and &pi[1]
is undefined behavior.
Setting a breakpoint on pi[1] = -4;
and running the program:
This is the output with pi = &j; pi = &i;
Breakpoint 1, main (argc=1, argv=0x7fffffffe428) at tmp.c:12
12 pi[1] = -4;
(gdb) p &j
$1 = (int *) 0x7fffffffe334
(gdb) p &i
$2 = (int *) 0x7fffffffe330
(gdb) p &pi
$3 = (int **) 0x7fffffffe338
(gdb) p &pi[1]
$4 = (int *) 0x7fffffffe334
(gdb) c
Continuing.
i = 100, j = -4, *pi = 100
[Inferior 1 (process 2890) exited normally]
(gdb)
&pi[1]
points to j
by chance
This is the output without pi = &j; pi = &i;
12 pi[1] = -4;
(gdb) p &j
$1 = (int *) 0x7fffffffe33c
(gdb) p &i
$2 = (int *) 0x7fffffffe32c
(gdb) p &pi
$3 = (int **) 0x7fffffffe330
(gdb) p &pi[1]
$4 = (int *) 0x7fffffffe330
(gdb) c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x000000000040056d in main (argc=1, argv=0x7fffffffe428) at tmp.c:13
13 printf("i = %d, j = %d, *pi = %d\n", i, j, *pi);
(gdb) p pi
$5 = (int *) 0x7ffffffffffc
With pi[1] = -4 (0xfffffffc)
the pointer pi
is modified pointing to a page where the process isn't allowed to read from, so the segmentation fault occurs.
You did not print pi
, &pi
and &pi[1]
(which is UB), which would be of interest.
The answer to your question is:
The compiler is free to decide where and in which order it arranges the variables in the stack frame. As you changed the source code of the function the compiler can decide differently. Additionally, &pi[1]
can point anywhere, as it is undefined behavior.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With