0

私はこれらの2つの構造体を持っています:

#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;

  typedef struct attrElem {
      char *attrName;
      char *attrValue;
   }Attr_Element,*pAttr_Element;

そして私はこの関数を書きました:

pAttr_Element getXmlAttrArray(pXml_Element node) {
    return node->attr_arr;
}

いくつか質問があります。

  1. なぜ違法なのですか?関数を次のように変更すると、機能します{pAttr_Element* getXmlAttr....}が、理由がわかりません。

構造体の中に、配列へのポインターがあります。ここで、すべてのセルはタイプpAttr_Elementのポインターです。または、配列へのポインタではありませんか?道に迷いました :(

  1. 関数を次のように変更しても機能しないのはなぜAttr_Element getXmlAttrArray(..)ですか?私が戻るとき:node->attr_arr返品タイプは何ですか?

  2. pAttr_elementsの配列へのポインタを返すために構造体を変更するにはどうすればよいですか?

ありがとうございました!

4

3 に答える 3

1

フィールドはのattr_arr配列でありpAttr_Element、ではありませんpAttr_Element。したがって、として返すことはできませんpAttr_Element
Cでは、配列はポインターではありませんが、多くの場合、ポインターに減衰します。を書き込むreturn node->attr_arrと、配列はポインタに減衰し、ポインタが返されます。

構造体には、のxml_Element配列へのポインタが含まれていませんpAttr_Element。実際には100のそのような構造が含まれています。

于 2012-08-05T07:56:16.117 に答える
0

コーディングスタイルに関するいくつかの考え:

これは、の意味に関する一般的な誤解です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バイト幅のレジスタがあります。以上です。配列を返したい場合は、大きなメモリのコピーを返す必要があります。これは、マシンでは効率的に実行できません。ただし、ポインタを返すだけで、返されたポインタを呼び出し元から簡単に読み取ることができます。

知恵の最後の言葉、配列は配列であり、ポインターはポインターです。いくつかの文脈ではそれらは交換可能ですが、文脈を考慮せずにそれらが同じであると考えるのは間違いです。

于 2012-08-05T12:25:45.603 に答える
-3

pAttr_Elementは、Attr_Elementへのポインタです。

Cでは、配列はポインターです。

attr_arrは、pAttr_Elementの配列です。つまり、一連のpAttr_Elementsへのポインター、つまり、Attr_Elementのポインターへのポインターです。

于 2012-08-05T07:56:36.460 に答える