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[])

配列パラメーターを変更した後に表示された "Bad access" エラーは、while ループに起因します。関数宣言を修正した後、arrayPointer[i]is has type struct node *. ポインターを介して構造体メンバーにアクセスしているため、.(ドット) 演算子を次のように変更する必要があります->

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

これで、twalberg のアドバイスに従って、値をitem直接割り当てることができます。

arrayPointer[i] = item;

修正が必要な問題がもう 1 つあります。arrayPointer[i]はポインター型であるため、null 値を持つことができます。ポインターを逆参照する前にその条件を確認する必要があります。そうしないと、プログラムがセグメンテーション違反でクラッシュする可能性があります。

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

編集:コードが「古いアドレスから値を奇妙に削除する」という懸念の背後にある「理由」の追加説明。

元のコードでは、 に渡すsourceNode->childrenappendAtEndOfArray、コンパイラは型の不一致のために警告を発行しますが、とにかくコードを生成します。渡す値と関数が期待する値は両方ともメモリアドレスであるため、これを行うことができます.ポインタの「タイプ」は、ポインタが参照するメモリをコンパイラがどのように扱うかを決定するだけなので、実際のデータ変換は必要ありません.行った。

私のマシン、32 ビット x86 プラットフォームでは、ポインターは 4 バイトで、struct node型は 252 バイトです (char 型と bool 型をそれぞれ 4 バイトまでパディングするため)。の最初の要素にappendAtEndOfArray代入する場合(元のコードから):itemarrayPointer

arrayPointer[i]=*item;

システムは、252 バイトのデータを構造体から、4 バイトのポインターを保持するためのメモリー位置にコピーします。その結果、次の 248 バイトarrayPointer[i]が上書きされます。ノードは配列に割り当てられるため、配列内の次のノードの一部nodesが上書きされます。

たとえば、呼び出しを考えてみましょう

appendAtEndOfArray(destinationNode,sourceNode->children);

sourceNode->children配列が空だったと仮定するとdestinationNode、0 番目の要素に割り当てられます。sourceNode->children割り当ては実際には構造体の内容全体を 0 番目の要素のメモリ位置に書き込んでいるので、これは(120 バイト)の 30 要素すべてとsourceNode->parents(別の 120 バイト) のすべてを上書きし、別の 12 バイトのデータが残ります。ノード配列の次の要素。(私のマシンでは)namevisitedメンバーの両方をカバーします。

于 2012-10-30T20:28:24.333 に答える