2012-03-21 90 views
-1

我不明白什麼是錯誤的在程序中。我正在定義一個指向結構數組的指針。馬洛克已經有足夠的記憶了。初始化數組元素。然後使用fwrite將數組寫入二進制文件。然後嘗試讀取相同的內容,返回到另一個指向類似數組的指針,該數組具有足夠的內存malloc'ed。將Struct的數組寫入二進制文件

#include<stdio.h> 

typedef struct ss{ 
int *p; 
char c; 
double d; 
char g; 
float f; 
} dd; 

main(){ 

dd (*tt)[5]; 
int i=0,a[5]={4,1,6,9,3}; 
tt=malloc(sizeof(struct ss[5])); 
for(i=0;i<5;i++){ 
    tt[i]->p=malloc(sizeof(int)); 
    tt[i]->p=&a[i]; 
    tt[i]->c=(char)('a'+i); 
    tt[i]->d=(double)(5.234234+i); 
    tt[i]->g=(char)('A'+i); 
    tt[i]->f=(float)(15.234234+i); 
} 

FILE *F; 
F=fopen("myfile","w+b"); 
size_t l; 
l=fwrite(tt,sizeof(*tt),1,F); 
fseek(F,0,SEEK_SET); 
//printf("sizeof(dd)=%d sizeof(*tt) =%d bytes written %d\n",sizeof(dd),sizeof(*tt),l); 

dd (*xx)[5]; 

xx=malloc(sizeof(struct ss[5])); 
l=fread(xx,sizeof(*xx),1,F); 

for(i=0;i<5;i++){ 
printf("%d, %c,%f,%c,%f\n",*(xx[i]->p),xx[i]->c,xx[i]->d,xx[i]->g,xx[i]->f); 
} 
printf("Date Read %d \n",l); 
for(i=0;i<5;i++){ 
free(xx[i]->p); 
} 
free(xx); 
free(tt); 
fclose(F); 
remove("myfile"); 
} 

輸出:
4,A,5.234234,A,15.234234
分段故障

回答

0

你指針的使用不正確。在此代碼段:

dd (*xx)[5]; 

xx=malloc(sizeof(struct ss[5])); 
l=fread(xx,sizeof(*xx),1,F); 

for(i=0;i<5;i++){ 
printf("%d, %c,%f,%c,%f\n",*(xx[i]->p),xx[i]->c,xx[i]->d,xx[i]->g,xx[i]->f); 
} 

您正在聲明XX作爲指針以5「DD」結構的陣列。這是奇怪的地方。它是指向五個結構的指針,而不是五個結構的數組。

It would look something like this in memory: 

dd[0] = [{p, c, d, g, f}, {p, c, d, g, f}, {p, c, d, g, f}, {p, c, d, g, f}, {p, c, d, g, f}] 
dd[1] = [{p, c, d, g, f}, {p, c, d, g, f}, {p, c, d, g, f}, {p, c, d, g, f}, {p, c, d, g, f}] 
... 
dd[4] = [{p, c, d, g, f}, {p, c, d, g, f}, {p, c, d, g, f}, {p, c, d, g, f}, {p, c, d, g, f}] 

Instead of the intended: 
dd[0] = {p, c, d, g, f} 
dd[1] = {p, c, d, g, f} 
... 
dd[4] = {p, c, d, g, f} 

當你從0迭代至5,每個數組訪問正在推進您的陣列的sizeof(SS [5])中存儲的代替的sizeof(SS)字節字節。拿出額外的指針。

dd* xx; 
xx = (dd*)malloc(sizeof(dd) * 5); 
l = fread(xx, sizeof(dd), 5, F); 

for(i = 0; i < 5; ++i) { 
    printf("%d, %c, %f, %c, %f\n", xx[i].p, , xx[i].c, xx[i].d, xx[i].g, xx[i].f); 
} 

此外,您的結構有問題。如果它是這樣直接寫入磁盤的,它不能包含指針。因此你的'int * p''成員需要改爲'int p;'。否則,如果您從單獨的應用程序讀取此文件,則您存儲的指針不會再指向整數,而是指向未分配的內存。

Writing application: 
    int *p = 0x12345 ---> 5 
0x12345 gets stored in the file for p. 

Writing application reads the file. 
    int *p = 0x12345 ---> 5 
The pointer still points at the same memory because it is still the same memory 
    layout. 

New application reads the file. 
    int *p = 0x12345 ---> ????? 
The pointer doesn't point to a known piece of memory because the memory layout 
    has changed in this new instance of the application. This could crash or 
    cause a security issue. 
1

你不寫,你以爲你是你的數據,因爲你錯誤地訪問tt。你的錯誤訪問是一致的,因此你可以讀出第一條記錄,但第二條記錄遠不及你認爲的那樣 - 事實上,它被寫入未初始化的內存並且從未保存過。試圖訪問重新加載的數據顯示了這一點。另外,結構中的int *不能正確地寫出來,因爲你的程序是如何構造的 - 如果你試圖單獨載入文件,這是錯誤的的程序。 fwritefread不能跟着你的int*,因爲它只是把你的結構看作是一個位模式 - 它忠實地重建你的指針,但是現在你有一個指向你實際上沒有做任何事情的隨機塊的指針!然而,在這種情況下,你的指針仍然有效,因爲你從不重寫數據,但是這是特定於寫入文件,不刷寫內存,並且在沒有關閉程序的情況下重新讀入的情況 - 這不是文件寫作的現實場景。 There's another StackOverflow question that explains this bug in more detail.

總之,這裏的你是如何訪問內存中的更大的問題,與其他行刪除:

dd (*tt)[5]; 
//... 
tt=malloc(sizeof(struct ss[5])); 
for(i=0;i<5;i++){ 
    tt[i]->p=malloc(sizeof(int)); 
    tt[i]->p=&a[i]; 
    //... 
} 

C聲明被讀取The Clockwise Spiral Rule,所以讓我們看看我們已經說過tt並將其與我們如何使用它進行比較。

tt是變量名稱。右邊是一個右括號,所以我們繼續處理當前的範圍。我們遇到一個*,然後匹配paren,然後是一個靜態數組大小,然後是一個類型。使用順時針螺旋規則,tt是指向數組(大小5)dd的指針。這意味着如果你解引用tt(使用(*tt)),你會得到一個dd[5],或者,如果你喜歡這樣想(C肯定會這樣),一個指向一個足夠容納你的結構的內存塊開始的指針。更重要的是,這就是你所說的。 C對指針類型來說實際上並不是很挑剔,這就是爲什麼即使你犯了一個嚴重的類型錯誤,你的代碼也會被編譯。

您的malloc語句是正確的:它正在初始化tt,並且內存位置是操作系統承諾的有足夠空間用於您的五個ss。因爲C不會像數組大小邊界檢查那樣愚蠢的事情,一個struct ss的5元素數組保證是單個struct ss的大小的5倍,所以你實際上可能寫了malloc(5 * sizeof(dd)),但是寫它的任何一種方式很好。

但是,讓我們看看會發生在這裏:

tt[i]->p=malloc(sizeof(int)); 

嗯,哦。 tt指向結構dd的數組的指針,但您已將其作爲指針陣列結構化爲dd

你想要什麼:

  • 提領tt
  • 查找指針數組的i個元素dd
  • 轉至字段p
  • 一個指向其分配給空間一個int

你究竟得到了什麼:

  • 查找i th元素在指針數組到的dd
  • 解除引用它陣列,將它視爲指針dd,由於C不知道數組和指針
  • 之間的差
  • 轉到間接到外地p
  • 一個指針分配給它的空間的int

i爲0時,此功能正常工作,因爲數組中的第零個元素和數組本身位於相同的位置。 (一個數組沒有頭,C_不理解數組和指針之間的區別,並且允許你交替使用它們,這就是爲什麼這個編譯完成的原因。)

i不是0時,的記憶。現在你正在寫信給你的指針發生的任何記憶!它實際上是一個指針,但是你告訴C它是一個數組,並且它相信你,在它的位置上添加了1個元素寬度,並試圖完成所有這些操作。你正在使用數組的地方,你應該使用指針,並指出你應該使用數組的地方。

您只寫入您爲元素0分配的內存。除此之外,您正在寫入無關的內存,並且運氣不好(在您的情況中運氣不好),導致程序無法正常運行。(如果有的話,你會比較容易找到這個有罪的線)。當你分配的內存,第一個元素是有效的,其餘的是垃圾,並且你的fread導致數據結構有一個有效的元素,然後隨機堆垃圾,當你試圖解引用一個指針(這隻會是有效的,因爲程序沒有結束)導致崩潰。

這裏訪問您的指針到陣列的正確方法:

(*tt)[i].p=malloc(sizeof(int)); ...

此外,你分配內存,然後馬上忘記你唯一的參考吧,這是一個記憶泄漏,因爲你正在用指向你正在初始化所有東西的靜態數組的引用覆蓋指針。使用這個來代替:

*((*tt)[i].p)=a[i]

我強烈建議你學習A Tutorial on Pointers and Arrays的全部。這將有助於您避免將來出現這類問題。

請注意,在以完全相同的方式打印其內容時,您的文字是錯誤地讀取xx

+0

我知道寫一個文件指針是一個壞主意。我在做這個練習只是爲了更好地理解指向數組的指針。你非常清楚地表示感謝。我將讀取該數組的指針鏈接。 mem漏洞捕獲+1。我改變了指針現在只保存靜態數組地址的代碼。 – Pkp 2012-03-21 14:38:53