关于c指针的问题

时间:2011-01-21 08:50:44

标签: c pointers

这只是我脑海中的一个疑问

这是下面显示的代码

          main()
          {
                  int *p,*q;
                  int a =20;
                  p = q;
                  p = &a;
                  free(p);
                  printf("The values of p and q are %d and %d\n",*p,*q);
           }

我怀疑的是,如果我们释放指针p,为此指针分配的内存将被释放并返回到空闲的内存池,因此在这种情况下,因为q也指向p,所以取消引用q应该给出错误我的理解。我说得对吗? 我在开发C ++编译器中运行了这个程序,令我惊讶的是它显示了两个指针的值。 在这种情况下,我们是否将指针q称为悬空指针?

提前多多感谢 麦迪

7 个答案:

答案 0 :(得分:4)

尝试在此处释放p会调用undefined behavior - 您只能释放malloc(或calloc,或realloc或strdup)。在这种情况下,您将释放指向堆栈变量a的指针,这是不允许的。

同样适用于解除引用*q - q中的值未初始化,因此取消引用它也会导致未定义的行为。严格地说,p = q也是未定义的*,但实际上简单地复制未初始化变量的值往往不会导致太多的问题本身(只是不要指望该值有意义)

当您调用未定义的行为时,可能会发生任何 - 这包括但不限于:

  • 马上崩溃
  • 稍后在一些不相关的代码中崩溃
  • 在不崩溃的情况下破坏某些数据
  • 破坏您认为安全的磁盘上的某些数据
  • 联系您的备份服务器并破坏备份
  • 允许触发计算机错误控制的黑客
  • Summoning demons through your nasal passages
  • 以上
  • 的任何组合
  • 有时候,什么都没有。

编译器需要提供任何类型的有用错误消息,尽管可能在某些情况下会这样做。

简而言之,不要这样做,但如果你这样做,不要指望它以任何一种特定的方式打破。这些类型的东西有一种有趣的方式,在代码的完全不同的部分看起来像错误。

* - 根据C99 6.2.6.1,如果C实现具有指针类型的陷阱表示,则变量的未指定初始值可能是陷阱表示,此时通过{{1}读取它} lvalue调用未定义的行为。

答案 1 :(得分:1)

如何从堆栈中释放内存?

不计算!

答案 2 :(得分:1)

你应该阅读指针并更好地理解它们。 Advice

p = q

q是一个未初始化的指针,您指定p指向同一个未指定的内存区域。

p = &a;

这没关系,现在p包含a的地址,但q仍然未初始化

free(p);

a存储在堆栈中,而不是堆中。可以这样做:

int *a = malloc(sizeof(int)); // allocates memory and stores location
*a = 20;                      // modifies allocated memory
p = a;                        // have a second pointer to the same zone
free(p);                      // frees the allocated memory: now dereferencing either p or a is a sin.

答案 3 :(得分:0)

您尝试在指向堆栈分配内存的指针上调用free(),并且这是未定义的行为,请不要这样做。仅针对从free()获得的指针调用malloc()

答案 4 :(得分:0)

a是一个自动变量,并且applyinf free(p)其中p =& a是一个错误,你很快就可以面对其他内存,因为你标记为一个不可用的空闲块内存。

答案 5 :(得分:0)

尝试使用freemalloccalloc未获得的realloc内存会导致未定义的结果。有时它会像继续运行并给你愚蠢的结果一样愚蠢。有时它会做一些更有用的事情:

$ ./a.out
*** glibc detected *** ./a.out: munmap_chunk(): invalid pointer: 0x00007fff8393bd5c ***
======= Backtrace: =========
/lib/libc.so.6(+0x774b6)[0x7f7a30bc04b6]
./a.out[0x400526]
/lib/libc.so.6(__libc_start_main+0xfe)[0x7f7a30b67d8e]
./a.out[0x400439]
======= Memory map: ========
00400000-00401000 r-xp 00000000 08:03 675233                             /tmp/a.out
00600000-00601000 r--p 00000000 08:03 675233                             /tmp/a.out
00601000-00602000 rw-p 00001000 08:03 675233                             /tmp/a.out
00f04000-00f25000 rw-p 00000000 00:00 0                                  [heap]
7f7a30933000-7f7a30948000 r-xp 00000000 08:03 228559                     /lib/libgcc_s.so.1
7f7a30948000-7f7a30b47000 ---p 00015000 08:03 228559                     /lib/libgcc_s.so.1
7f7a30b47000-7f7a30b48000 r--p 00014000 08:03 228559                     /lib/libgcc_s.so.1
7f7a30b48000-7f7a30b49000 rw-p 00015000 08:03 228559                     /lib/libgcc_s.so.1
7f7a30b49000-7f7a30cc3000 r-xp 00000000 08:03 228962                     /lib/libc-2.12.1.so
7f7a30cc3000-7f7a30ec2000 ---p 0017a000 08:03 228962                     /lib/libc-2.12.1.so
7f7a30ec2000-7f7a30ec6000 r--p 00179000 08:03 228962                     /lib/libc-2.12.1.so
7f7a30ec6000-7f7a30ec7000 rw-p 0017d000 08:03 228962                     /lib/libc-2.12.1.so
7f7a30ec7000-7f7a30ecc000 rw-p 00000000 00:00 0                      
7f7a30ecc000-7f7a30eec000 r-xp 00000000 08:03 228501                     /lib/ld-2.12.1.so
7f7a310cc000-7f7a310cf000 rw-p 00000000 00:00 0
7f7a310ea000-7f7a310ec000 rw-p 00000000 00:00 0                      
7f7a310ec000-7f7a310ed000 r--p 00020000 08:03 228501                     /lib/ld-2.12.1.so
7f7a310ed000-7f7a310ee000 rw-p 00021000 08:03 228501                     /lib/ld-2.12.1.so
7f7a310ee000-7f7a310ef000 rw-p 00000000 00:00 0                      
7fff8391d000-7fff8393e000 rw-p 00000000 00:00 0                          [stack]
7fff839df000-7fff839e0000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
Aborted

我的C库有助于向我提供失败的地址,并且非常有助于转储内存映射(这对我来说是新的!谢谢!),这让我可以快速看到地址在堆栈中

答案 6 :(得分:0)

这给了我在Valgrind运行时所期望的确切行为:

==8839== Invalid free() / delete / delete[]
==8839==    at 0x4024836: free (vg_replace_malloc.c:325)
==8839==    by 0x8048440: main (boom.c:10)
==8839==  Address 0xbe9a5164 is on thread 1's stack

我这样做是因为我很好奇,因为有几个人报告了同样的行为。

p的地址(由free()取消引用)是所谓的悬空指针,因此对它的任何操作都是未定义的。我编译时没有使用优化(-O0)和调试符号(-g)来产生更好的说明,但无论如何它都会爆炸。

正常运行程序只会产生分段错误。在valgrind下进行分析时,该程序实际上已完成(当printf()同时取消引用爆炸性指针时的其他投诉):

==8839== Use of uninitialised value of size 4
==8839==    at 0x8048445: main (boom.c:11)
==8839==
The values of p and q are 20 and 459916161
==8839==
==8839== HEAP SUMMARY:
==8839==     in use at exit: 0 bytes in 0 blocks
==8839==   total heap usage: 0 allocs, 1 frees, 0 bytes allocated

但这只是因为Valgrind正在捕捉SEGV。

未定义的行为就是这样,未定义。这是可怕的“哇,在我的机器上工作!”的主要原因之一。错误:))