简体   繁体   English

变量的C内存管理

[英]C memory management for variables

I am new to C and I currently have some troubles. 我是C的新手,目前我遇到了一些麻烦。 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. 代码因SegFault失败。 Some investigation with gdb: 用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?? 但是,没有2行,代码工作正常,因为我和j似乎交换内存中的位置 - 但为什么??

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

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是一个指针,当你这样做时,你会指向一个整数

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. 您正在访问不受您控制的内存或未分配的内存,因此会导致未定义的行为,从而导致seg错误。

Statement pi[1] = -4; 声明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; 相当于*(pi+1) = -4; . Pointer one past the object i is allowed but dereferencing it will invoke undefined behavior. 指针一个超过对象i被允许但是取消引用它将调用未定义的行为。

C11:6.5.6 Additive operators: C11:6.5.6添加剂操作员:

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

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; 8如果指针操作数和结果都指向同一个数组对象的元素,或者指向数组对象的最后一个元素,则评估不应产生溢出; 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. 当然pi[1]&pi[1]是未定义的行为。

Setting a breakpoint on pi[1] = -4; pi[1] = -4;上设置断点pi[1] = -4; and running the program: 并运行该程序:

This is the output with pi = &j; pi = &i; 这是pi = &j; pi = &i;的输出pi = &j; pi = &i; 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 &pi[1]偶然指向j

This is the output without pi = &j; pi = &i; 这是没有pi = &j; pi = &i;的输出pi = &j; pi = &i; 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. pi[1] = -4 (0xfffffffc)的情况下,指针pi被修改为指向不允许读取进程的页面,因此发生分段错误。

You did not print pi , &pi and &pi[1] (which is UB), which would be of interest. 你没有打印pi&pi&pi[1] (这是UB),这将是有意义的。

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. 另外, &pi[1]可以指向任何地方,因为它是未定义的行为。

I could guess that pi=&j prevents the compiler from giving to j a register memory. 我猜猜pi=&j阻止编译器给j一个寄存器存储器。 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. 因此, pi[1]是对j的引用,但没有它, j在寄存器中, pi[1]是对先前存储的ebp寄存器的值的引用。 As ebp becomes garbled, the process crashes when tryng to return from main() . ebp变为乱码时,当tryng从main()返回时,进程崩溃。

Having said this, I should repeat what was said by others: it's undefined behaviour in both cases . 话虽如此,我应该重复其他人所说的话: 在两种情况下都是未定义的行为

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM