2

私はCプログラミングに本当に慣れていませんが、ポインターの使用とtypedef構造体の使用の概念を理解しようとしています。

プログラムで使用する必要がある次のコードスニペットがあります。

typedef struct
{
    char* firstName;
    char* lastName;
    int id;
    float mark;
}* pStudentRecord;

これが何をするのか正確にはわかりません-私にはObjective-Cでインターフェースを使用するのと似ているように見えますが、そうではないと思います。

そして、私はこの行を持っています

pStudentRecord* g_ppRecords;

私は基本的に数pStudentRecordg_ppRecords基づいていくつかを追加する必要があります。タイプのオブジェクトにメモリを作成して割り当てる方法は理解していますがpStudentRecord、実際に複数のオブジェクトをに追加する方法がわかりませんg_ppRecords

4

4 に答える 4

2

中括弧内に記述された構造体へのポインタを定義します。これはより簡単な例です。

typedef struct {
    int x;
    int y;
}Point,* pPoint;

int main(void) {
   Point point = {4,5};
   pPoint point_ptr = &point;
   printf("%d - %d\n",point.x,point_ptr->x);

   pPoint second_point_ptr = malloc(sizeof(Point));
   second_point_ptr->x = 5;
   free(second_point_ptr);
}
于 2012-09-09T19:15:55.977 に答える
2

1つ目は、名前のない構造体と、pStudentRecordそれへのポインタである型を宣言します。g_ppRecords2番目は。へのポインタであることを宣言しますpStudentRecord。言い換えると、構造体へのポインタへのポインタです。

2番目を「ポインタの配列」と考える方がおそらく簡単です。そのため、とをg_ppRecords[0]指す場合があります。(これは、レコード構造体を指します。)pStudentRecordg_ppRecords[1]

これに追加するには、ポインタがどのように格納されているか、つまり、格納されているポインタの数をどのように知るかを知る必要があります。どこかにサイズがあります。これは、サイズの場合N、少なくともN * sizeof(pStudentRecord*)メモリが割り当てられていることを意味し、アイテムg_ppRecords[0]g_ppRecords[N-1]保持しNます。または、NULLで終了します。これは、サイズのN場合、少なくとも(N+1) * sizeof(pStudentRecord*)メモリが割り当てられ、アイテムをg_ppRecords[0]保持g_ppRecords[N-1]し、保持して、文字列の終わりをマークすることを意味します。Ng_ppRecords[N]NULL

この後、を作成または追加するのは簡単g_ppRecordsです。

于 2012-09-09T19:21:23.883 に答える
1

構造体は複合データ型です。つまり、他の変数を含む変数です。あなたはObjectiveCに精通しているので、それを「データのみ」のクラスのような小さなものと考えるかもしれません。つまり、メソッドのないクラスです。これは、関連情報をまとめて保存し、1つのユニットとして渡すことができる方法です。

Typedefは、Cの組み込み型の同義語として独自のデータ型に名前を付ける方法です。これにより、コードが読みやすくなり、コンパイラーがより多くのエラーをキャッチできるようになります(プログラムの意図についてコンパイラーに効果的に教えます。 )典型的な例は

typedef int BOOL;

(古いANSI Cには組み込みのBOOL型はありません。)

これは、次のようなことができることを意味します。

BOOL state = 1;

そして、パラメーターを受け取る関数を宣言してから、コンパイラーに、実際にはsだけであってもsをBOOL渡していることを確認させます。BOOLint

void flipSwitch(BOOL isOn); /* function declaration */
...
int value = 0;
BOOL boolValue = 1;
flipSwitch(value); /* Compiler will error here */
flipSwitch(boolValue); /* But this is OK */

struct StudentRecordしたがって、上記のtypedefは、学生レコード構造体の同義語を作成しているため、学生レコードを毎回呼び出すことなく渡すことができます。これにより、コードがよりクリーンで読みやすくなります。あなたの例では、ここにそれ以上のものがあることを除いて。私が今説明したのは:

typedef struct {
  char * firstName;
  char * lastName;
  int id;
  float mark;
} StudentRecord;

これで、次のようなことができます。

StudentRecord aStudent = { "Angus\n", "Young\n", 1, 4.0 };

また

void writeToParents(StudentRecord student) {
    ...
}

しかし*、typedefの後にはあります。これは、StudentRecord自体をtypedefするのではなく、StudentRecordへのポインターを保持するデータ型をtypedefするためです。え?読む...

StudentRecordを渡し、メンバー変数を変更できるようにする場合は、変数自体ではなく、ポインターを渡す必要があるため、StudentRecordへのこのポインターが必要です。typedefはこれに最適です。これも、コンパイラが微妙なエラーをキャッチできるためです。上記でwriteToParentsは、StudentRecordの内容を読み取るだけで作成しました。グレードを変更したいとします。メンバーを直接変更できないため、単純なStudentRecordパラメーターを使用して関数を設定することはできません。したがって、ポインタが必要です。

void changeGrade(StudentRecord *student, float newGrade) {
  student->mark = newGrade;
}

*を見逃す可能性があることは簡単にわかります。そのため、代わりに、StudentRecordのポインター型をtypedefすると、コンパイラーが役立ちます。

typedef struct { /* as above */ } *PStudentRecord;

今:

void changeGrade(PStudentRecord student, float newGrade) {
  student->mark = newGrade;
}

両方を同時に宣言するのがより一般的です。

typedef struct {
  /* Members */
} StudentRecord, *PStudentRecord;

これにより、プレーンな構造体typedefとポインターtypedefの両方が得られます。

では、ポインタとは何ですか?別の変数のメモリにアドレスを保持する変数。シンプルに聞こえます。表面的にはそうですが、非常に微妙になり、非常に迅速に関与します。このチュートリアルをお試しください

于 2012-09-09T19:28:58.500 に答える
0

これは、構造体へのポインターの名前を定義しますが、構造体自体の名前は定義しません。次のように変更してみてください:

typedef struct
{
    char* firstName;
    char* lastName;
    int id;
    float mark;
} StudentRecord;

StudentRecord foo;
StudentRecord *pfoo = &foo;
于 2012-09-09T19:08:20.557 に答える