是否有任何理由不会将堆指针分配给数组?

Posted

技术标签:

【中文标题】是否有任何理由不会将堆指针分配给数组?【英文标题】:Is there any reason that a heap pointer would not get assigned to an array? 【发布时间】:2019-11-03 14:03:01 【问题描述】:

Node的结构如下:

struct Node 
    int data;
    Node *next;
    bool someBool;
;

我有以下几行:

    Node *hello = new Nodedata, cur, !new_head; // line A
    array[new_head_index] = hello;                // line B
                                                 // line C

new_head_index 的值在所有 3 行上都被 GDB 确认为 1。

GDB 确认,在 A、B 和 C 行,当我执行 p *hello(打印 hello 的内容)时,我得到:

(gdb) p *hello
$7 = data = 888, next = 0x8414e70, someBool = false

但是打印array@2 的内容(数组长度为2,在main 中声明为Node *heads[numHeads] = new Node0, nullptr, false, nullptr;)在B 行和C 行有这个(在行实际执行之前):

(gdb) p **array@2
$8 = data = 777, next = 0x8414e70, someBool = true, data = 33, next = 0x378, someBool = 112

(应该是777节点,我之前填过)。

在 A 行,它有:

(gdb) p **array@2
$9 = data = 777, next = 0x8414e70, someBool = true, data = 61265, next = 0x0, someBool = false

基本上,hello 没有分配给array[1]。这可能是什么原因?

这是一个最小的可重现示例: main.cc

#include <iostream>
#include <string>
#include "new_mod.h"
using namespace std;

int len(Node **array) 
    int i = 0, count = 0;
    while (array[i++])  ++count; 
    return count;


void attach(Node **array, int head, int index, int data) 
    Node *hello = new Nodedata, cur;
    array[new_head_index] = hello;


int main() 
    string command;
    int head;
    Node *array[numHeads] = new Node0, nullptr, nullptr;

    while (cin >> command) 
        if (command == "a") 
            int m, x;
            cin >> head >> m >> x;

            attach(array, head, m, x);
        
    


mod.h

#ifndef MOD_H
#define MOD_H
#include <ostream>

struct Node 
    int data;
    Node *next;
    bool someBool = false;
;

const int numHeads = 2;

void attach(Node **array, int head, int index, int data);
#endif

尝试输入此输入(我已将此文件命名为 a.in

a 0 0 777
a 0 1 888

g++ -Wall -g main.cc -o newe 编译,这样你就可以用gdb 做事了!

顺便说一下,这是我在 gdb 中为解决上述问题所做的:

gdb newe
b attach(Node**, int, int, int)
run <a.in
layout n
c
n
n
n
n
n
n
n          (comment: I did n until line Node *hello = new Nodedata, cur;)
p **array@2
n
n
p **array@2 (the problem is shown)

【问题讨论】:

minimal reproducible example 会更容易查看。 @PaulMcKenzie 好的,给你 【参考方案1】:

问题在于Node *array[2]Node **array同一件事,当您向GDB 询问p **array@2 时,您要求将数组解释为好像array 是一个双指针,不是数组。

您可以在开始输入循环之前观察到这一点:

(gdb) p *array@2
$1 = 0x55555556ae70, 0x0
(gdb) p *array[0]
$2 = data = 0, next = 0x0, someBool = false

在这里,您可以看到 array 处于预期状态:第一个节点全为零,第二个节点为 NULL。

但是当你这样做时:

(gdb) p **array@2
$3 = data = 0, next = 0x0, someBool = false, data = 4113, next = 0x3737203020302061, someBool = 55

您可以立即看到您没有查看正确的数据:您知道 array[1] 是 NULL,所以它不能指向 @ 987654330@ 里面有4113

我不相信print *array[0 .. N] 有 GDB 内置语法。 一种可能的解决方案是定义一个辅助函数(它可以很容易地概括为将数组名称和大小作为参数,但为了简单起见,这里保持微不足道):

(gdb) def parray
Type commands for definition of "parray".
End with a line saying just "end".
>print *array[0]
>print *array[1]
>end
(gdb) parray
$4 = data = 0, next = 0x0, someBool = false
Cannot access memory at address 0x0
(gdb) c
Continuing.

Breakpoint 1, attach (array=0x7fffffffdb70, head=0, index=1, data=888) at foo.cc:34
34          array[new_head_index] = hello;
(gdb) n
35      
(gdb) parray
$5 = data = 777, next = 0x55555556ae70, someBool = false
$6 = data = 888, next = 0x55555556ae70, someBool = false

【讨论】:

我什至不知道什么是双指针。但是当我一周前开始使用 gdb 时,我查找了如何执行“打印数组”,我发现了这个 SO 问题: ***.com/questions/14502236/…。而且我认为到目前为止,对于我过去尝试过的阵列来说,这一切都很好。那么这个答案错了​​吗? 答案没有错,print *array@2 工作正常。但是您不想打印数组元素的指针值;你想打印 dereferenced 指针,这是不同的。 另外,另一个问题是“如何将指针打印为数组”。这里你一个数组,所以简单的p array 可以打印它的值。 有什么区别?当我搜索“数组元素的指针值”时,我什么也找不到。你只是说地址吗?我的意思是 array 在这种情况下是一个指针数组,这就是为什么你必须取消引用它两次,否则它会给你地址(我认为“指针值”你可能是指地址),但如果它只是一个指针像intstruct 这样的东西,然后像p *array@2 这样的东西没有给我地址,它给了我实际的值.. 你如何解释这个? " "另外,另一个问题是'如何将指针打印为数组'。这里有一个数组,很简单p array 可以打印它的值。" p array 在我的示例中仅打印 $13 = (Node **) 0x7ffffffee150。这就是您所说的“数组”吗?这对我来说不是有用的信息。

以上是关于是否有任何理由不会将堆指针分配给数组?的主要内容,如果未能解决你的问题,请参考以下文章

是否有任何理由为啥我的 UITableViewCell 的覆盖 setHighlighted 不会被调用但 UITableViewDelegate 方法会?

是否有任何理由锁定队列?

在C ++中,是否有任何理由产生并立即加入一个线程,而不是直接调用该函数?

是否有任何理由继续使用 IntentService 处理 GCM 消息?

是否有任何理由对同一资源使用“Vary: *”和“Vary: Foo”响应?

是否有任何理由使用一个 DataContext 实例,而不是几个?