我有一个方法应该在数组的末尾添加一个“节点”。当我找到一个存储值的地方(有效)时,这会奇怪地从旧地址中删除该值。
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];
}
有人可以指出我做错了吗?
答案 0 :(得分:3)
您看到此行为是因为appendAtEndOfArray
的定义与您传递给它的参数之间存在类型不匹配。 NuclearGhost在评论中指出了这一点。正如他所说,函数声明需要更改为
void appendAtEndOfArray(struct node * item, struct node * arrayPointer[])
更改数组参数后看到的“错误访问”错误来自while循环。在更正函数声明后,arrayPointer[i]
的类型为struct node *
。由于您现在通过指针访问struct成员,因此.
(点)运算符必须更改为->
:
while (arrayPointer[i]->name != '\0') {
现在,您可以采取twalberg的建议直接指定item
的值:
arrayPointer[i] = item;
还有一个问题需要纠正:arrayPointer[i]
是指针类型,因此它可以具有空值。在取消引用指针之前需要检查该条件,否则程序可能会因分段错误而崩溃:
while (arrayPointer[i] && (arrayPointer[i]->name != '\0')) {
编辑:关于代码“奇怪地删除旧地址中的值。”的背后“原因”的补充说明。
在原始代码中,当您将sourceNode->children
传递给appendAtEndOfArray
时,编译器会因类型不匹配而发出警告,但无论如何都会生成代码。它可以这样做,因为你传入的值和函数所期望的值都是内存地址 - 指针的“类型”只是确定编译器如何处理指针所指的内存,所以不必实际的数据转换进行。
在我的机器上,一个32位的x86平台,指针是4字节,你的struct node
类型是252字节(由于填充char和bool类型最多4个字节,每个)。当appendAtEndOfArray
将item
分配给arrayPointer
的第一个元素时,(来自原始代码):
arrayPointer[i]=*item;
系统将252字节的数据从结构复制到一个用于保存4字节指针的内存位置。结果,覆盖arrayPointer[i]
之后的下一个248个字节。由于节点是在数组中分配的,这意味着nodes
数组中下一个节点的一部分将被覆盖。
例如,考虑调用
appendAtEndOfArray(destinationNode,sourceNode->children);
假设sourceNode->children
数组为空,因此destinationNode
将被分配给第0个元素。由于赋值实际上是将整个struct内容写入第0个元素的内存位置,因此会覆盖sourceNode->children
(120字节)的所有30个元素以及sourceNode->parents
的所有元素(另外120个字节) ,留下另外12个字节的数据溢出到节点数组中的下一个元素,(在我的机器上)覆盖了name
和visited
成员。