5

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?

10
  • 2
    Undefined behavior is undefined. It really is that simple. Also, what does "the code works fine" mean? What behavior do you consider fine for this code? Commented Mar 4, 2015 at 9:34
  • the code is a task in our class.. by working fine, i mean the printf prints: i = 100, j = -4, *pi = 100 -- pi[1] points on j, seemingly Commented Mar 4, 2015 at 9:39
  • If your teacher has no idea that pi[1] is undefined behavior, she's not a very good teacher. Commented Mar 4, 2015 at 9:40
  • @user2343039 But why is that "working fine"? What makes that behavior "fine" exactly? Commented Mar 4, 2015 at 9:46
  • 2
    @user2343039 You see, pointers in C is always a way to make mess: you can create a pointer, point at any (made up) address you like, change data at that address and you can even get away with it or endup in a segfault. So it's always a programmer's job to use pointers smartly. So if you're studying C pi[1] = -4; is UB. You shouldn't use ptr[ind] syntax to access just arbitrary locations. But your question, as you put it, is more about the way your particular compiler works, but not about how to do a proper C programming. Commented Mar 4, 2015 at 10:05

4 Answers 4

15

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.

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

4 Comments

Thanks, but why do the 2 lines change something in the code?
@user2343039 Once you have undefined behavior in your code anything can happen. So you are seeing crash. You can't expect some defined results by having undefined behavior in the code.. Get rid of it
it's not like I can get rid of it.. that code is part of the task. I wasn't me, who wrote that code..
@user2343039 Please understand how pointers work. When something works by having UB in the code it doesn't mean your code is clean. Those 2 lines doesn't make any sense as you keep changing the address to which the pointer should point.In the end you make it point to variable i which is fine but pi[1] is not fine. We can't explain UB
9

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.

Comments

1

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.

Comments

0

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.

1 Comment

the gdb output suggests that j was not assigned a register in either case

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.