2012-09-15 21 views
5

厳密には変更を加えずに、次のコードブロックを使用しなければなりません。構造体へのポインタの動的配列

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

pStudentRecord* g_ppRecords; 
int g_numRecords =0; 

ここで、g_ppRecordsは構造体へのポインタの配列であると考えられます。私は完全に理解するために失敗しています、アレイは、私が動的にg_ppRecordsに割り当てたメモリを試してみましたが、それは助けていない

type arrayname[size]; 

として定義されなければならないので、どのように声明pStudentRecords *g_ppRecords;を配列するg_ppRecordsを意味することができるということです。

g_ppRecords = (pStudentRecord*) malloc(sizeof(pStudentRecord*)*(g_numRecords+1)); 
+0

ポインタは単にアドレスを指しています。あなたは、あなたが望むように(スペースを使い果たすまで)、そのアドレスから始まるように多くのメモリを予約することができます。 – chris

+0

私はそれが貧しい問題だと思う、あなたはそれのためのスペースを割り当ててみるので、配列がそのような方法で定義できることを理解しているので、あなたは何を求めているのですか?ポインタのスペースを割り当てるのに十分ではありませんbtw pStudentRecordであり、pSt ... ord *ではないstructには、それを使用するために、struct自身のための場所を割り当てる必要があります! – Michael

答えて

1

pStudentRecordが構造体へのポインタとしてtypedefされることを確認してください。 Cのポインタは、そのブロックが1つの要素(通常の "スカラー"ポインタ)または10要素( "配列"ポインタ)を含むかどうかにかかわらず、単にメモリブロックの先頭を指します。次

char *s = "abcd"; 

で始まるメモリの一部にsポイントになりながらしたがって、たとえば、次のよう

char c = 'x'; 
char *pc = &c; 

は、文字'x'で始まるメモリの一部にpcポイントになります"abcd"(その後にヌルバイトが続きます)。タイプは同じですが、異なる目的に使用される可能性があります。

したがって、一度割り当てると、私はg_ppRecordsの要素にアクセスできます。 g_ppRecords[1]->firstName。 を使用します(但し、sizeof(pStudentRecord*)sizeof(pStudentRecord)は両方ともポインタ型なので等しくなります)。この配列を割り当てるには、g_ppRecords = malloc(sizeof(pStudentRecord)*(g_numRecords+1));を使用します。sizeof(pStudentRecord*)sizeof(pStudentRecord)は同じです。これにより、構造体の初期化されていない配列が作成されますポインタ。配列内の各構造体ポインタに対して、新しい構造体を割り当てることによって値を与える必要があります。問題の核心は、幸いなことに、あなたは、単一の構造を割り当てるかもしれない方法、すなわち

g_ppRecords[1] = malloc(/* what goes here? */); 

であることができます実際にsizeof内のポインタ間接参照:sizeofはコンパイラ構築物である

g_ppRecords[1] = malloc(sizeof(*g_ppRecords[1])); 

注こと。 g_ppRecords[1]が有効なポインタでなくてもタイプは有効なので、コンパイラは正しいサイズを計算します。

+0

g_ppRecords [1] =(pStudentRecord *)malloc(sizeof(char *)* 2 + sizeof(int)+ sizeof(float)); ? –

+0

優れたソリューションを追加しました。それは実際には明らかな解決策ではありません、それを考えるようになりました。 – nneonneo

+0

+1私にいくつかの新しいトリックを教えて... –

0

配列は、しばしばその最初の要素へのポインタで参照されます。あなたが10の学生レコードのために十分なスペースをmallocし、g_ppRecordsにそのスペースの先頭へのポインタを格納すると、g_ppRecords [9]はレコードポインタの長さを9に数え、そこにあるものを逆参照します。スペースを正しく管理していれば、十分な空き容量を確保しているため、配列の最後のレコードは何になりますか?

要するにスペースを割り当てておきたいそれが適切な長さであれば、配列として含めることができます。

g_numRecords + 1レコードのスペースを割り当てる理由がわかりません。 g_numRecordsの名前がわかりにくい場合を除き、必要以上に配列内に1つ以上のスペースがあります。

-1

ここで、g_ppRecordsは構造体へのポインタの配列であると考えられます。私が完全に理解していないのは、ステートメント* pStudentRecords g_ppRecords;配列を意味するg_ppRecordsを意味します。配列として定義する必要があります

タイプarrayname [サイズ];

ウムtype arrayname[size];これは静的スタックに格納された値のほとんどがそれの位置に依存して、配列を定義C.

の配列を定義する一方向の多くの方法ありますコンパイル時に配列のサイズを知る必要がありますが、これは現代のコンパイラの中には当てはまりません。

別の方法は、実行時に動的に配列を作成することです。したがって、コンパイル時にサイズを知る必要はありません。ポインタは動的に割り当てられたチャンクのアドレスを格納する変数です。このtype *array = malloc(sizeof(type) * number_of_items);のmallocがarrayに格納されたメモリアドレスを返すよう

簡単な例では、ものになるだろう、私たちは安全上の理由からの戻り値の型を型キャストしないでください。

手元の問題に戻ります。

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

pStudentRecord* g_ppRecords; 
int g_numRecords = 0; 

このtypedefが最もから少し異なっているが、このように構造体に}*基本的にそのポインタを注意:

pStudentRecord* g_ppRecords; 

は実際には:

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

それへのポインタなぜ彼らはtypedefをこのように定義するのか、それは私を超えています。私は個人的にそれを推奨しません、なぜですか?

よく1つの問題があります。どのようにして名前から構造体のサイズを取得できますか?単純なことはできません! sizeof(pStudentRecord)を使用すると、構造体のサイズを知らずに、typedef名を使ってポインタを割り当てることができないので、基礎となるアーキテクチャに応じて4または8が得られます。何ができるのですか?

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

g_ppRecords = malloc(sizeof(StudentRecord) * g_numRecords); 

このコードを作成した人や、あなたの懸念を維持している人に本当に連絡する必要があります。

g_ppRecords=(pStudentRecord) malloc((sizeof(char*) + 
            sizeof(char*) + 
            sizeof(int) + 
            sizeof(float)) *(g_numRecords+1)); 

これは1つの可能な方法のように見えるかもしれません、残念ながら、構造体約no guaranteesがあるので、構造体の合計サイズではなく、その複合体、実際に大きくすることができるので、実際に部材間にパディングをcontaingでき言及するにはおそらくアドレスが異なるでしょう。

EDIT

はどうやら我々は単に

ので、その型推論することによって、構造体のサイズを取得することができます

pStudentRecord g_ppRecords = malloc(sizeof(*g_ppRecords) * g_numRecords); 

が正常に動作します!

+0

ダウン投票者には詳しく説明していますか? –

+0

これは、構造定義をハードコーディングし(そしてパディングなどを無視する)、 'malloc'を使うのは本当に本当に悪い方法です。他の方法がないと言っても間違っています。私の解決策を見てください。書かれたコードは、まれではあるが、完全に有効で使用可能です。 – nneonneo

+0

私は**貧しい**道を言った、いずれにせよ私はそれを削除します。 –

3

EDIT: "BIG MISTAKE"セクションを更新しました。

Cスタイル(C++とは異なります)のtypedefのクイックレッスンと、それがどのようなものなのか、そしてその使い方です。

まず、基本的なtypedefトリック。あなたがIP1の宣言に*を入れていなかったにもかかわらず、ポインタ・ツー・タイプ-INT:

typedef int* int_pointer; 
int_pointer ip1; 
int *ip2; 
int a; // Just a variable 
ip1 = &a; // Sets the pointer to a 
ip2 = &a; // Sets the pointer to a 
*ip1 = 4; // Sets a to 4 
*ip2 = 4; // Sets a to 4 

IP1とIP2は同じタイプです。それは宣言の中に*ありました。

トピックを切り替える。 あなたは、実行時に動的にこれを行うには

int array1[4]; 

として配列を宣言するの話、あなたが行う可能性があります:今

int *array2 = malloc(sizeof(int) * 4); 
int a = 4; 
array1[0] = a; 
array2[0] = a; // The [] implicitly dereferences the pointer 

、我々はポインタの配列をしたい場合は何?

int *array1[4]; 
int a; 
array1[0] = &a; // Sets array[0] to point to variable a 
*array1[0] = 4; // Sets a to 4 

この配列を動的に割り当てましょう。

int **array2 = malloc(sizeof(int *) * 4); 
array2[0] = &a; // [] implicitly dereferences 
*array2[0] = 4; // Sets a to 4 

int **に注目してください。つまり、ポインタからintへのポインタへのポインタです。私たちが選択すれば、ポインタtypedefを使うことができます。

typedef int* array_of_ints; 
array_of_ints *array3 = malloc(sizeof(array_of_ints) * 4); 
array3[0] = &a; // [] implicitly dereferences 
*array3[0] = 4; // Sets a to 4 

最後の宣言には*が1つしかありません。それは、そのうちの1つが「typedefの中に」あるからです。その最後の宣言で、ints(int *)への4つのポインタからなるサイズ4の配列ができました。

ここではオペレータの優先度を指摘することが重要です。逆参照演算子[]は*より優先されます。 SO私たちがやっていること、絶対的に明確になるこのです:

*(array3[0]) = 4; 

、のは、構造体とのtypedefに話題を変えてみましょう。

struct foo { int a; }; // Declares a struct named foo 
typedef struct { int a; } bar; // Typedefs an "ANONYMOUS STRUCTURE" referred to by 'bar' 

なぜ匿名の構造体をtypedefしますか?まあ、読みやすいように!

struct foo a; // Declares a variable a of type struct foo 
bar b;  // Notice how you don't have to put 'struct' first 

機能を宣言...

funca(struct foo* arg1, bar *arg2); 

我々はARG2の前で '構造体' を置く必要はありませんでしたどのように参照してください?

今、私たちは、あなたが使用する必要があり、コードは、このように構造を定義することを参照してください。

typedef int* array_of_ints; 

が比較:我々の前にポインタの配列をしたかに似ている

typedef struct { } * foo_pointers; 

side-by-side

typedef struct { } * foo_pointers; 
typedef int* array_of_ints; 

唯一の違いは、struct {}とintの違いです。私たちのfoo_pointersで

、我々のようなfooへのポインタの配列を宣言することができます。

foo_pointers fooptrs[4]; 

今、私たちは私たちがアクセスすることはできません匿名の構造体へのポインタ店4その配列を持っています。

トピックスイッチ!

UNFORTUNATELY FOR YOU、あなたの先生は間違いを犯しました。上記のfoo_pointers型のsizeof()を見ると、構造体のサイズではなく、その構造体へのポインタのサイズを返します。 32ビットプラットフォームの場合は4バイト、64ビットプラットフォームの場合は8バイトです。これは、構造体そのものではなく、構造体へのポインタをtypedefするためです。 sizeof(pStudentRecord)は4を返します。

したがって、構造自体にスペースを割り当てることはできません。しかし、コンパイラはこの愚かさを許します。 pStudentRecordは、メモリを有効に割り当てるために使用できる名前/型ではなく、匿名の「概念」構造体へのポインタですが、そのサイズをコンパイラに渡すことができます。

pStudnetRecord g_ppRecords [2]; pStudentRecord * record = malloc(sizeof(* g_ppRecords [1]));

より良い練習はこれを行うことです。

typedef struct { ... } StudentRecord; // Struct 
typedef StudentRecord* pStudentRecord; // Pointer-to struct 

今は明確な方法で、構造体StudentRecord年代を作る能力だけでなく、pStudentRecordさんとそれらへのポインタを持っていると思います。

あなたが強制する方法は非常に悪い習慣ですが、現時点ではまったく問題ではありません。 intを使った簡単な例に戻りましょう。

私の人生を複雑にするtypedefを作成したいが、ここで起こっているコンセプトについて説明したいのですが?古いintコードに戻りましょう。あなたが見ることができるように

typedef int* array_of_ints; 
int *array1[4]; 
int **array2 = malloc(sizeof(int *) * 4); // Equivalent-ish to the line above 
array_of_ints *array3 = malloc(sizeof(array_of_ints) * 4); 
int a, b, c, d; 
*array1[0] = &a; *array1[1] = &b; *array1[2] = &c; *array1[3] = &d; 
*array2[0] = &a; *array2[1] = &b; *array2[2] = &c; *array2[3] = &d; 
*array3[0] = &a; *array3[1] = &b; *array3[2] = &c; *array3[3] = &d; 

、我々はpStudentRecordでこれを使用することができます。

pStudentRecord array1[4]; 
pStudentRecord *array2 = malloc(sizeof(pStudentRecord) * 4); 

一緒にすべてを入れて、それがその論理的に次の:

array1[0]->firstName = "Christopher"; 
*array2[0]->firstName = "Christopher"; 

は等価です。 (注意:上記のように正確に行うのではなく、実行時に文字列にchar *ポインタを割り当てることは、既に十分なスペースが割り当てられていることがわかっている場合にのみOKです)。

これは実際に最後のビットを1つだけ表示します。私たちがこのすべての記憶で何をしているのか?どのようにそれを解放するのですか?

free(array1); 
free(array2); 

とポインタ、匿名の構造体の型定義、および他のものの深夜レッスンの終わりがあります。

+0

ご意見ありがとうございます。それが私を助けました! – Rachael

関連する問題