2012-09-15 86 views
5

我必須使用以下代碼塊來完成學校作業,嚴格地說,沒有任何修改。指向結構的動態指針數組

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

pStudentRecord* g_ppRecords; 
int g_numRecords =0; 

這裏g_ppRecords應該是指向結構體的指針數組。什麼我完全不理解的是,如何才能聲明pStudentRecords *g_ppRecords;意味着g_ppRecords是一個數組,因爲數組應該被定義爲

type arrayname[size]; 

我試圖分配內存動態g_ppRecords,但是這沒有幫助。

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

指針只是指向一個地址。您可以根據需要從該地址開始保留儘可能多的內存(直到空間用完爲止)。 – chris

+0

我認爲這是一個很差的問題,你明白可以用這種方式定義數組,因爲你嘗試爲它分配一個空間,所以你在問什麼?,僅僅爲指針分配一個空間是不夠的結構,這是btw pStudentRecord而不是pSt ... ord *,爲了使用它,你還需要爲struct it自己分配一個地方! – Michael

回答

1

觀察到pStudentRecord是typedef'd作爲指向結構的指針。 C中的指針只是指向一個內存塊的開始,無論該塊是否包含1個元素(一個普通的「標量」指針)或10個元素(一個「數組」指針)。因此,例如,下面的

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

使得pc指向一塊內存以字符'x'開始,雖然以下

char *s = "abcd"; 

使得s指向一塊內存,與開始"abcd"(後跟一個空字節)。類型是相同的,但它們可能用於不同的目的。

因此,一旦分配,我可以通過例如訪問g_ppRecords的元素。 g_ppRecords[1]->firstName

現在,分配這個數組:你想使用g_ppRecords = malloc(sizeof(pStudentRecord)*(g_numRecords+1));(儘管注意sizeof(pStudentRecord*)sizeof(pStudentRecord)是相等的,因爲兩者都是指針類型)。這使得未初始化的結構數組指針。對於數組中的每個結構指針,你需要通過分配一個新的結構來給它賦值。問題的關鍵是,你會如何分配的單一結構,即

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

幸運的是,你實際上可以取消引用指針在sizeof

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

注意sizeof是一個編譯器結構。即使g_ppRecords[1]不是有效的指針,類型仍然有效,因此編譯器將計算正確的大小。

+0

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

+0

增加了一個更好的解決方案。這實際上並不是一個明顯的解決方案,可以想一想。 – nneonneo

+0

+1教我幾個新的技巧... –

0

數組通常用指向其第一個元素的指針引用。如果你爲malloc足夠的空間存放10個學生記錄,然後在g_ppRecords中存儲一個指向該空間開始的指針,g_ppRecords [9]將向前計數9個記錄指針長度並取消引用那裏的內容。如果你正確地管理你的空間,那裏的東西將是你的數組中的最後一條記錄,因爲你保留足夠的空間,10

總之,你已經分配的空間,但是和你想你可以把它如果它是正確的長度,包括作爲一個數組。

我不知道爲什麼你的g_numRecords + 1點的記錄分配空間。除非g_numRecords被混淆命名,否則這是數組中超出需要的空間。

-1

這裏g_ppRecords應該是指向結構體的指針數組。我完全不明白的是,如何聲明* pStudentRecords g_ppRecords;意味着g_ppRecords是一個數組。作爲數組應該定義爲

type arrayname [size];

type arrayname[size]; UMM是許多方式中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,它超越了我,我個人不推薦它,爲什麼?

好的一個問題是,我們如何通過名稱獲得結構體的大小?簡單,我們不能!如果我們使用sizeof(pStudentRecord),我們將得到48,這取決於底層架構,因爲這是一個指針,不知道結構的大小,我們不能使用它的typedef名稱真正動態分配它,所以我們可以做什麼,聲明一個第二結構像這樣:

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

這可能看起來是一種可能的方式,不幸的是,有no guarantees約結構,因此它們實際上可以方含在構件之間的填充,從而該結構的總尺寸可以實際上更大然後其組合成員,而不是要提到的地址可能會有所不同。

編輯

顯然,我們可以通過簡單地推斷出它的類型

因此得到了結構的大小:

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

工作正常!

+0

給下來的選民照顧詳細說明? –

+0

這是一種非常糟糕的方法,因爲您對結構定義進行了硬編碼(並忽略填充等),所以使用'malloc'。你說沒有其他辦法可以做到這一點是不正確的;看我的解決方案。所寫的代碼是完全有效且可用的,儘管有些不尋常。 – nneonneo

+0

我確實說**較差的方式,無論如何,我會刪除它。 –

3

編輯:「大錯誤」部分更新。

C風格的快速教訓(從C++不同!)類型定義,以及爲什麼它是怎麼回事,以及如何使用它。

首先,一個基本的typedef把戲。

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,即使你沒有把一個* IP1的聲明。這*代替了聲明。

切換主題。 你說話聲明數組作爲

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 

看看在最後的聲明中只有一個*嗎?這是因爲其中之一是「在typedef」。與去年的聲明,你現在有一個包含4個指向整數(INT *)大小爲4的數組。

這裏必須指出的運算符優先級是很重要的。解引用運算符[]優先於*之一。所以我們要做的就是:

*(array3[0]) = 4; 

現在,讓我們將主題更改爲structs和typedefs。

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

爲什麼你會輸入一個匿名結構?那麼,爲了可讀性!

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 struct { } * foo_pointers; 

這類似於我們是怎麼做的指針之前的數組:

typedef int* array_of_ints; 

比較並排

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

唯一的區別是一個是struct {},另一個是int。

隨着我們foo_pointers,我們可以聲明數組的指針到foo這樣:

foo_pointers fooptrs[4]; 

現在我們有了一個數組,商店4個指向一個匿名的結構,我們無法訪問。

TOPIC SWITCH!

不適合你,你的老師犯了一個錯誤。如果查看上面的foo_pointers類型的sizeof(),會發現它返回指向該結構的指針的大小,而不是結構的大小。對於32位平臺,這是4個字節,對於64位平臺是8個字節。這是因爲我們輸入了一個指向結構的指針,而不是結構本身。 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的,以明確的方式的能力。

雖然你不得不使用的方法是非常糟糕的做法,但目前這不是一個問題。讓我們回到我們使用整數的簡單示例。

如果我想要使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 *指針賦給一個字符串只是確定的)。

這只是真正帶來了最後一點。我們如何處理所有這些我們malloc'd的內存?我們如何釋放它?

free(array1); 
free(array2); 

還有一個關於指針,匿名結構的typedefs和其他東西的深夜課程的結束。

+0

感謝您的評論。這幫助我了! – Rachael