コーディングスタイルに関するいくつかの考え:
これは、の意味に関する一般的な誤解ですtypedef
。人々はマクロ定義を使用しているかのようにそれを使用します。
それを理解することtypedef
は、ストレージクラス分類子であることが非常に重要です。マクロ定義によって達成できることの便利な名前ではありません。参照する単純な名前で非常に複雑な型を作成できる場合、その真の力はtypedef
報われます。
例 :
typedef void (*ptr_to_fun)(char *p)
このステートメントは、 charへのポインターを引数として取り、何も返さない関数へのポインターは、これからptr_to_funを呼び出すことができることを示しています。
だから私は次のようなステートメントを持つことができます
ptr_to_fun ptr = my_fun
しかし、ほとんどの場合、キーワードtypedef
を非表示にするために使用されるのは少し残念です。struct
これは私の意見では悪い習慣です。なぜなら、それはほとんど成果を上げませんが、新しいcプログラマーを混乱させるからです。(これは、セマンティクスよりも構文について不平を言う、オブジェクト指向の群衆が圧倒的に多いためかもしれません。)Cは簡単にオブジェクト指向にすることができます。Linuxカーネルコードを見てください。多重継承などがあります。struct
キーワードを隠す必要はありませんでした。キーワードtypedef
を非表示にするためのものではありません。struct
それはより大きくそして重要な用途を持っています。
あなたのコードは...
#define M 100
#define N 100
typedef struct xml_Element {
pData_Element data;
pAttr_Element attr_arr[M];
struct xml_Element *parent;
struct xml_Element *children[N];
int depth;
int num_of_children;
int num_of_attr;
} Xml_Element,*pXml_Element;
つまりxml_Element
、それは実際には新しいタイプであるということですstruct xml_Element
。またpxml_Element
、実際にはタイプの新しいタイプstruct xml_Element *
です。
さて、あなたの問題に行きましょう。
あなたの機能は
pAttr_Element getXmlAttrArray(pXml_Element node) {
return node->attr_arr;
}
したがって、pAttr_Element
タイプを返します。あなたはtypedef
それを編集しました。つまり、実際にはタイプの略ですstruct attrElem *
。
これで、初期構造にpAttr_Element
配列ができました。つまり、あなたがやろうとしているのは、配列を返すことです。これを返すことはできません。この配列へのポインタを返すことができます。これで、配列はタイプになりstruct attr_Elem *pAttr_Elem[M]
ます。structattr_elemへのポインタの配列。したがって、この配列へのポインタと互換性のある戻り型は、'struct attr_Elem **pAttr_Elem[M]のようになります。. after typedef it will be like 'pAttr_Element *
また、cでは配列を返すことはできません。配列にはポインタが含まれている場合がありますが(あなたの場合のように)。しかし、それは問題ではありません。配列を返すことはできません。
cがこれを許可しない理由を考えてください。
関数は2つの方法でデータを返すことができます。戻り値を保持するために指定されたレジスタを使用できます。また、フレームポインターを操作して、フレームが忘却された後にアクセスできるスタックにあるものをプッシュすることもできます(ただし、標準的な方法ではありません)。
x86_64アーキテクチャでは、ネイティブポインタ変数を保持できる8バイト幅のレジスタがあります。以上です。配列を返したい場合は、大きなメモリのコピーを返す必要があります。これは、マシンでは効率的に実行できません。ただし、ポインタを返すだけで、返されたポインタを呼び出し元から簡単に読み取ることができます。
知恵の最後の言葉、配列は配列であり、ポインターはポインターです。いくつかの文脈ではそれらは交換可能ですが、文脈を考慮せずにそれらが同じであると考えるのは間違いです。