1

我有一个方法应该在数组末尾添加一个“节点”。当我找到一个存储值的地方(有效)时,这奇怪地从旧地址中删除了值。

void appendAtEndOfArray(struct node * item,struct node * arrayPointer){
    int i=0;
    while (arrayPointer[i].name!='\0') {
        i++;
    }
    arrayPointer[i]=*item; // after this the original memory at &item is changed to '\0'
}

这可能很容易,但我是 C 和整个指针的新手....

我这样调用方法:

void addVertice(char source, char destination,int cost){
    struct node * sourceNode = addNode(source);
    struct node * destinationNode = addNode(destination);
    appendAtEndOfArray(destinationNode,sourceNode->children);
    appendAtEndOfArray(sourceNode,destinationNode->parents);
}

我的节点定义如下:

struct node            {
    char name;
    bool visited;
    int distance;
    struct node *children[30];
    struct node *parents[30];
} nodes[30];

struct node * addNode(char name){
    int n=getNodeByName(name); // if exists reuse
    if (n==-1) {
        n=++lastNodeIndex;
    }
    nodes[n].name = name;
    nodes[n].visited=false;
    return &nodes[n];
}

有人可以指出我做错了什么吗?

4

1 回答 1

3

您看到这种行为是因为您的定义appendAtEndOfArray和传递给它的参数之间存在类型不匹配。NuclearGhost 在评论中指出了这一点。正如他所说,函数声明需要更改为

void appendAtEndOfArray(struct node * item, struct node * arrayPointer[])

您在更改数组参数后看到的“错误访问”错误来自 while 循环。更正函数声明后,arrayPointer[i]is 具有 type struct node *。由于您现在通过指针访问结构成员,因此.(点)运算符必须更改为->

while (arrayPointer[i]->name != '\0') {

现在您可以按照 twalberg 的建议item直接分配 的值:

arrayPointer[i] = item;

还有一个问题需要更正:arrayPointer[i]是指针类型,所以它可以有一个空值。在取消引用指针之前需要检查该条件,否则程序可能会因分段错误而崩溃:

while (arrayPointer[i] && (arrayPointer[i]->name != '\0')) {

编辑:您担心代码“奇怪地从旧地址中删除值”背后的“为什么”的附加解释。

在您的原始代码中,当您传入 时sourceNode->childrenappendAtEndOfArray编译器会由于类型不匹配而发出警告,但无论如何都会生成代码。它可以这样做是因为您传入的值和函数期望的值都是内存地址——指针的“类型”只是决定编译器如何处理指针所指的内存,因此不必进行实际的数据转换执行。

在我的机器上,一个 32 位 x86 平台,指针是 4 字节,你的struct node类型是 252 字节(由于将 char 和 bool 类型填充到每个 4 字节)。当appendAtEndOfArray分配item给 的第一个元素时arrayPointer,如(来自原始代码):

arrayPointer[i]=*item;

系统将结构体中的 252 字节数据复制到用于保存 4 字节指针的内存位置。结果,后面的 248 个字节arrayPointer[i]被覆盖。由于节点是在数组中分配的,这意味着数组中下一个节点的一部分nodes将被覆盖。

例如,考虑调用

appendAtEndOfArray(destinationNode,sourceNode->children);

假设sourceNode->children数组为空,因此destinationNode将分配给第 0 个元素。由于分配实际上是将整个结构内容写入第 0 个元素的内存位置,这将覆盖(120 个字节)的所有 30 个元素sourceNode->children以及sourceNode->parents(另外 120 个字节)的所有元素,留下另外 12 个字节的数据溢出到节点数组中的下一个元素,它(在我的机器上)涵盖了namevisited成员。

于 2012-10-30T20:28:24.333 回答