2010-02-08 132 views
5

tl; dr - 请您在下面的第一个代码片段中展开4条评论?具体是什么意思derefC/C++指针问题

我是一个很长时间的Java开发人员,希望学习C++。我遇到了针对开发者的this website

int x, *p, *q; 
    p = new int; 
    cin >> x; 
    if (x > 0) q = &x; 
    *q = 3;     // 1. deref of possibly uninitialized ptr q 
    q = p; 
    p = new int;   // 2. potential storage leak (if x != 0 this 
          //  memory will not be returned to free storage) 
    *p = 5; 
    delete q; 
    *q = 1;     // 3. deref of deleted ptr q 
    q = p; 
    if (x == 0) delete q; 
    (*p)++;     // 4. deref of possibly dangling ptr p (if x is zero) 

尽管我认为我理解指针是如何工作的,但我发现这些注释很难理解。

我把;

  1. 我们要么分配X(& *当然Q)在3或当q!= & X则Q有一个公正的价值,因为它是未初始化的,我们刚才随机分配的一块内存到值3.我不确定如何解引用未初始化的东西?
  2. 这很好
  3. 取消引用已删除的指针有什么问题?在'删除q'之后* q是无意义的?
  4. 悬挂指针有什么问题?即使我们仍然有指向它的指针,现在我们已经删除了它,内存是否可以重新分配?

我想我的基本误解是关于只是声明一个int指针,这是否也分配内存?它是堆栈还是堆?

解除引用是否意味着'读取指针地址处的值'?我认为我的混淆是,我认为它会失去对某些数据的引用;

int *x; 
x = new int; 
*x = 5; 
x = new int; // Dereferencing the first bit of memory allocated. 

感谢您的耐心,我希望这有一定道理的问题,

GAV株系

+0

对指针可能发生的所有问题的良好总结。 – 2010-02-08 11:58:47

+0

另一方面,变量名称使其不可能遵循逻辑。真正的代码永远不会接近这个复杂的(或者说,不应该是) – 2013-01-30 19:24:19

回答

6

简单地说:一个指针,其值,你可能有兴趣在一个变量的地址

间接引用是访问该值的行为 - 在前面加上了*(对其操作)的。指针变量。访问可以用于阅读,写作或两者兼而有之。

  1. 如果您没有初始化指向有效地址(或特殊值NULL)的指针 - 您不知道该变量包含的是什么。解引用将尝试将所有内容都视为地址。这是未定义的行为 - 所有投注都关闭,任何事情都可能发生,但如果幸运的话,最终会出现陷阱/硬件异常。

  2. 没错。因为,p正在保存您分配的某个内存的地址。不释放系统资源会导致泄漏。解引用已删除的指针与解引用未初始化的指针相同 - 您不知道它可能包含的值。

  3. 同样,UB。

  4. 是的。你的UB为x == 0。晃来晃去的指针是危险的,因为它们在最不合时宜的时候爬起来,格式化你的硬盘并且再也看不到。不可能合理地证明你的程序将如何表现。

+0

+1。摇晃的指针也指向记忆,你将永远不能再次到达。 – ALOToverflow 2010-02-08 12:42:10

+0

您点击的关键点是第二句 - 我不知道术语解引用意味着访问存储在变量地址中的值。 我认为这意味着像'无关紧要' - 删除最后一个内存引用而不删除它。 谢谢 – gav 2010-02-08 14:15:56

1

回应你的需要:

  1. x的值从读流。这可能会失败,使x未初始化(存储垃圾值)。所以if的行为是不可靠的,因此它可能不会将地址分配给q。因此,分配*q = 3将写入随机存储器地址。

  2. 这不好!没有垃圾收集。第一个对象分配在堆上,它的地址分配给了p。现在您分配第二个指针并覆盖指针以保存新地址。旧地址丢失了,所以没有人可以通过p删除它。后面有一个delete q,它是p的地址的副本,但该声明取决于x(这是不可靠的)的值。

  3. 这不是指针已被删除。这是指向的对象。该指针仍然保存着一个指向曾经是有效对象的值,但现在是垃圾。如果你解除引用,你的程序将会有“未定义的行为”。

  4. 是的。运行时系统(比如它)没有跟踪指向对象的指针。

2

在:

  1. 可以通过从地址解引用它来具体内存see Pointer dereference doc.分配q指针。但是由于if条件将其设置为地址x它可以指向随机存储单元(未初始化),如果x <= 0
  2. 在上面的行中,您将q设置为指向与p相同的内存地址。然后为p分配新的内存。然后你分配p指向的新内存。
  3. 上面的行删除了q指向的内存分配。此内存地址现在可供系统使用。在此之后,您为内存赋值并不属于您。
  4. 如果x == 0则返回到qp指向的系统内存。并再次尝试使用不属于你的内存。如果x != 0也没有delete p - 因此内存不会返回到系统。
3

增加了更多的评论中,线下:

int x, *p, *q; 
    p = new int; 
    cin >> x; 
    if (x > 0) q = &x; 
    *q = 3;     // <--- 1. deref of possibly uninitialized ptr q 
          // 
          // q has never been set or is set to point at a non 
          // allocated memory location (if x > 0) 
          // 
          // If x is zero q is uninitialized (has random value). 
          // Therefore de-referencing it to set what it points at 
          // to 3 has undefined behavior. 

    q = p; 
    p = new int;   // <--- 2. potential storage leak (if x != 0 this 
          //  memory will not be returned to free storage) 
          // 
          // This comment is not true. The value pointed at by p 
          // was transferred to q before p was re-assigned. Thus 
          // there is no potential memory leak. Both p and q are 
          // now valid pointers. 
    *p = 5; 
    delete q; 
    *q = 1;     // <--- 3. deref of deleted ptr q 
          // 
          // In the line above you returned the memory pointed at 
          // by q back to memory management routines (via delete). 
          // Technically q still points at the memory but you no 
          // longer own that memory and thus writing to it has 
          // undefined behavior (because the memory management 
          // system could have unloaded that chunk from virtual 
          // memory or re-used it some other way). 
    q = p; 
    if (x == 0) delete q; 
    (*p)++;     // <--- 4. deref of possibly dangling ptr p (if x is zero) 
          // 
          // q is reassinged to have the same pointer value as p. 
          // Then If x is zero we delete the pointer q (thus 
          // returning it to the memory management pool). Since p 
          // and q are the same pointer they both become invalid at 
          // point. Thus de-referencing p is undefined behavior if 
          // x is zero (because the memory was returned (via delete) 

1我们要么分配X(& *当然Q)在3或当q = & X那么q有!因为它是未初始化的,我们刚刚分配了一个随机片段的内存值3.我不确定如何解引用未初始化的内容?

见下文:

3这有什么错解引用删除指针?在'删除q'之后* q是无意义的?

内存属于别人(内存管理(或线程化应用可能已经被重新分配给其他线程)。写入内存不属于你了不确定的行为。

4有什么问题悬摆指针吗?现在是内存可行的重新分配,我们已经删除了它,即使我们仍然有一个指向它?

相同的注释为3(只是因为你保留了无效的指针呢不代表什么)

解除引用的意思是'读取指针地址的值'?我认为我的混淆是,我认为它会失去对某些数据的引用;

是的:这就是全部意思。
但是,如果你不拥有这种记忆可能会发生令人讨厌的事情。

  • 如果指针指向内存中未映射到物理内存的位置,则会出现某种形式的分段错误。
  • 如果内存属于内存管理例程,并且开始将随机值(如上面的3)写入内存管理例程,则可能会损坏内存管理结构,从而导致程序在任何内存管理发生时崩溃。
  • 如果内存属于堆栈并开始写入随机值(如上面的3),则可能会覆盖另一个随机变量或函数退出时使用的返回地址。
2

如果您不知道“引擎盖下”发生了什么,这是一个很难的课题。 C++是一种'裸机'编程语言,很少使任何安全。

看着你提供的代码和感兴趣的标记点:

第一行有:int x, *p, *q;它声明并定义在堆栈上一些变数,但不会初始化它们。在运行时,C++也不记得发生了这种情况。编译时你可能会得到一些警告,但除此之外,你必须跟踪你脑海中的事情。

因此,在行1.我们不知道q是否是&x或不。如果q没有被初始化,那么它可能指向任何地方,但是C++不知道,并且会尝试将值3写入某处的某个内存。这一点的答案是C++不跟踪指针值。

在第3.行,C++正在尝试向某段内存写入一个整数值,但这次它在堆上和多线程程序中可能已在此行执行时重新分配。所以,不幸的是q*q保留的含义,但它不可能意味着我们想要的。

在行4.其与3.相同的问题,但只有在(x==0),如你所说,是的,即使我们已经删除它,内存可能已被重新分配。

声明一个int指针只为指针分配内存单独和在堆栈上。

解引用指针意味着访问指针所指向的内存,用于读取或写入。

关于您的第二片的代码:用于读取或写入到存储器,该指针指向

int *x;   <-- Declares a pointer and allocates it on the stack 
x = new int; <-- Allocate a new int on the heap and remember its address in x 
*x = 5;   <-- Overwrite the new int on the heap. 
x = new int; <-- Another allocation and remember its address in x 
        Now we have forgotten where the first allocation was 

解除引用。如果你只是读或写指针本身,那么它总是安全的。这就是为什么你可以传递一个指针,只有在第一次解除引用时才会遇到麻烦。