变量的C内存管理

use*_*039 5 c pointers

我是C的新手,目前我遇到了一些麻烦.请看下面的代码:

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;
}
Run Code Online (Sandbox Code Playgroud)

代码因SegFault失败.用gdb进行一些调查:

(gdb) print &j
$1 = (int *) 0x7fffffffde80
(gdb) print &i
$2 = (int *) 0x7fffffffde84
Run Code Online (Sandbox Code Playgroud)

但是,没有2行,代码工作正常,因为我和j似乎交换内存中的位置 - 但为什么??

(gdb) print &j
$1 = (int *) 0x7fffffffde84
(gdb) print &i
$2 = (int *) 0x7fffffffde80
Run Code Online (Sandbox Code Playgroud)

我问我的老师,但不幸的是她不知道.

提前致谢!!

编辑:通过工作正常,我的意思是printf打印:i = 100,j = -4,*pi = 100 - pi [1]点j,看似

问题是,为什么这两条线改变了什么?

Gop*_*opi 15

pi 是一个指针,当你这样做时,你会指向一个整数

pi[1] = -4;
Run Code Online (Sandbox Code Playgroud)

您正在访问不受您控制的内存或未分配的内存,因此会导致未定义的行为,从而导致seg错误.


hac*_*cks 9

语句pi[1] = -4;调用未定义的行为.什么事情都可能发生.您可能会得到预期或意外的结果.

pi[1] = -4;相当于*(pi+1) = -4;.i允许指向对象的指针,但取消引用它将调用未定义的行为.

C11:6.5.6添加剂操作员:

7出于这些运算符的目的,指向不是数组元素的对象的指针与指向长度为1的数组的第一个元素的指针的行为相同,其中对象的类型为其元素类型.

8如果指针操作数和结果都指向同一个数组对象的元素,或者指向数组对象的最后一个元素,则评估不应产生溢出; 否则,行为未定义.如果结果指向数组对象的最后一个元素之后,则不应将其用作已计算的一元*运算符的操作数.


问题是,为什么这两条线改变了什么?

答案是,它是因为未定义的行为.


456*_*976 1

我的编译器如下:

当然pi[1],这&pi[1]是未定义的行为。

设置断点pi[1] = -4;并运行程序:

这是输出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) 
Run Code Online (Sandbox Code Playgroud)

&pi[1]j偶然指向

这是没有的输出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
Run Code Online (Sandbox Code Playgroud)

由于pi[1] = -4 (0xfffffffc)指针pi被修改为指向不允许进程读取的页面,因此会发生分段错误。

您没有打印pi, &piand &pi[1](即 UB),这会很有趣。

你的问题的答案是:

编译器可以自由决定在堆栈帧中排列变量的位置和顺序。当您更改函数的源代码时,编译器可以做出不同的决定。此外,&pi[1]可以指向任何地方,因为它是未定义的行为。