2016-07-04 11 views
2

私はヘッダーファイルを作成し、リンクされたリストを作成する方法について学び始めながら実装を分離する方法を学んでいます。私はlinked_list.hlinked_list.c、およびmain.cファイルを作成しました。 main.cポインタを作成しない限り、struct typedef'edを作成しようとするとエラーが発生し、それが動作します。私はなぜこれが理解できないのですか?誰かがこれを説明してもらえますか?私の構造体をポインタとして宣言しなければならないのはなぜですか?

linked_list.h

#ifndef LINKED_LIST_H_ 
#define LINKED_LIST_H_ 

typedef struct ListNode_ ListNode; 

#endif // LINKED_LIST_H_ 

linked_list.c

#include <stdio.h> 
#include <stdlib.h> 
#include "linked_list.h" 

struct ListNode_ { 
    int data; 
    ListNode *next; 
}; 

main.c

#include <stdio.h> 
#include <stdlib.h> 
#include "linked_list.h" 

int main() { 

    ListNode node1; // why can't I do this? 
    ListNode *node2; // but this works 
} 
+2

'main.c'に' struct ListNode_'の定義が含まれていないので、その翻訳単位でその型のオブジェクトを作成することはできません。 –

+0

私は初心者です。以前は用語翻訳ユニットについて聞いたことがありません。正しく動作させるために何か変更する必要がありますか? ListNodeをメインでポインタを使って作成できますが、それがないとできないのはなぜですか? – Austin

+2

'ListNode_'構造体定義を' .h'ファイルに移動します。ヘッダーファイルにどのような情報を格納する必要があるかについては、[この回答](http://programmers.stackexchange.com/a/167751)を参照してください。 – Jezor

答えて

2

これは、ListNodeとListNode_の両方が宣言されているにもかかわらず、ListNode_のみが定義されているからです。コンパイラは、ListNodeオブジェクトに何が含まれているのかわからないのです。

はい、ListNodeへのポインタを持つことができます。ただし、使用することはできません。

//ListNode node1; // why can't I do this? 
ListNode *node2; // but this works 
node2->foo(); 

と入力してください。不完全なタイプについての同じコンパイルエラーメッセージが表示されます。 にはしかないので、ポインタはどこかに格納されています。なぜなら、それはまさにアドレスなので、プログラムはポインタが何を指しているか知る必要があるからです。

はい、node1は使用しませんが、それでもエラーが表示されます。どうして?プログラムは自動的にnode1用のスペースを割り当てなければならないので、そのスペースがどのくらいあるべきか分かりません。もちろん、コンストラクタを自動的に呼び出すことになっていることは言うまでもありませんが、これもやはり定義されていません。

これは、あなたがそのポインタを持つことが許されているなぜここ

struct ListNode_ { 
    int data; 
    ListNode *next; 
}; 

もあります。

私はファイルが正しくリンクされていないという事実を無視しています。なぜなら、それはコメントで議論されていて、とにかくこの問題とは関係がないからです。

2

あなたがmain.cListNodeを宣言する際、コンパイラが何をするかを考える必要があります。 typedefはstruct ListNode_と表示されますが、のコンパイル時にはstruct ListNode_が何であるかわかりません。これを修正するには、struct ListNode_の定義をlinked_list.hに移動する必要があります。

ListNodeへのポインタの宣言は、この場合はstruct ListNode_のような未知のサイズのオブジェクトへのポインタを宣言することができるため、機能します。しかし、完全に宣言したい場合はListNode、コンパイラはそれがどのサイズかを知る必要があります。しかし、コンパイラは各ソースファイルを別々にコンパイルするので、struct ListNode_linked_list.cにありません。したがって、エラーが発生します。

2

複数のファイルを使用しましたので、あなたはもう少しすべてのファイルがstructの同じ見解を持っていることを確認するために注意する必要がしました。main.cは、その構造が何であるかを知らないので、あなたが実際の変数を宣言することはできません

struct Listnode_ { 
    int data; 
    struct ListNode_ *next; 
}; 

typedef struct Listnode_ Listnode; 

理由である:特に、あなたはそうのように、ヘッダファイルlinked_list.h自体の内部にそれをINGのstruct ListNodetypedefを定義することを考慮すべきです、そのためにメモリを割り当てることはできません。 CANしかし、すべてのポインタが内部的に同じ型を持っているので、ポインタは宣言します。これは、PIMPLEコンセプト(インプリメンテーションへのポインタ)と呼ばれ、何が何であるかわからなくても、インプリメンテーションを指すポインタを宣言できます。これは、Cが提供する抽象化の一形態です。

関連する問題