Reputation: 57
I have a method that should add a 'node' to the end of an array. When i've found a place to store the value (which works), this strangely removes the value from the old address.
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'
}
This is probably very easy, but I am new to C and the whole pointer thing ....
I call the method like this:
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);
}
My node is defined like this:
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];
}
Can someone please point out what I am doing wrong?
Upvotes: 1
Views: 136
Reputation: 634
You are seeing this behavior because you have a type mismatch between the definition of appendAtEndOfArray
and the arguments you are passing into it. NuclearGhost pointed this out in the comments. As he stated, the function declaration needs to be changed to
void appendAtEndOfArray(struct node * item, struct node * arrayPointer[])
The "Bad access" error you saw after changing the array parameter comes from the while loop. After correcting the function declaration, arrayPointer[i]
is has type struct node *
. Since you are now accessing the struct member through a pointer, the .
(dot) operator must be changed to ->
:
while (arrayPointer[i]->name != '\0') {
Now you can take twalberg's advice to assign the value of item
directly:
arrayPointer[i] = item;
There is one more problem that needs to be corrected: arrayPointer[i]
is a pointer type, so it can have a null value. That condition needs to be checked before dereferencing the pointer, or the program will likely crash from a segmentation fault:
while (arrayPointer[i] && (arrayPointer[i]->name != '\0')) {
Edit: Additional explanation of the "why" behind your concern that the code "strangely removes the value from the old address."
In your original code, when you passed sourceNode->children
into appendAtEndOfArray
, the compiler issues a warning because of the type mismatch but generates the code anyway. It can do this because the value you pass in and the value the function expects are both memory addresses -- the "type" of the pointer simply determines how the compiler treats the memory the pointer refers to, so no actual data conversion has to be performed.
On my machine, a 32-bit x86 platform, pointers are 4-bytes and your struct node
type is 252 bytes (due to padding the char and bool types up to 4-bytes, each). When appendAtEndOfArray
assigns item
to the first element of arrayPointer
, as (from the original code):
arrayPointer[i]=*item;
The system copies the 252 bytes of data from the struct to a memory location that was intended to hold a 4-byte pointer. As a result, the next 248 bytes after arrayPointer[i]
are overwritten. Since the nodes are allocated in an array, that means that part of the next node in the nodes
array will be overwritten.
For example, consider the call
appendAtEndOfArray(destinationNode,sourceNode->children);
Assume the sourceNode->children
array was empty, so destinationNode
would be assigned to the 0th element. Since the assignment is actually writing the entire struct contents to the memory location of the 0th element, this would overwrite all 30 elements of sourceNode->children
(120 bytes) as well as all of sourceNode->parents
(another 120 bytes), leaving another 12 bytes of data that spills into the next element in the nodes array, which (on my machine) covers both the name
and visited
members.
Upvotes: 3