user2343039
user2343039

Reputation: 133

C memory management for variables

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?

Upvotes: 5

Views: 200

Answers (4)

4566976
4566976

Reputation: 2499

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.

Upvotes: 1

haccks
haccks

Reputation: 106012

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.

C11:6.5.6 Additive operators:

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.

Upvotes: 9

Matt
Matt

Reputation: 15091

I could guess that pi=&j prevents the compiler from giving to j a register memory. Thus with it pi[1] is a reference to j, but without it j is in a register and pi[1] is a reference to a value of previously stored ebp register. As ebp becomes garbled, the process crashes when tryng to return from main().

Having said this, I should repeat what was said by others: it's undefined behaviour in both cases.

Upvotes: 0

Gopi
Gopi

Reputation: 19864

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.

Upvotes: 15

Related Questions