我不明白该计划中的错误是什么。我正在定义一个结构数组的指针。 Malloc足够的记忆力。初始化数组元素。然后使用fwrite将数组写入二进制文件。然后尝试读取相同的内容,返回另一个指向类似数组的指针,该数组具有足够的内存malloc。
#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,一个,5.234234,A,15.234234
分段错误
答案 0 :(得分:1)
您没有按照自己的想法编写数据,因为您错误地访问了tt
。您的错误访问是一致的,因此您可以读出第一条记录,但第二条记录远不及您认为的那样 - 事实上,它被写入未初始化的内存而从未保存过。尝试访问重新加载的数据显示了这一点。另外,你的结构中的int *无法按照你编写的方式正确写出,但是由于你的程序结构如此,这是没有意义的 - 如果你试图在一个文件中加载文件就错了单独运行程序。 fwrite
和fread
无法关注您的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];
//...
}
使用The Clockwise Spiral Rule阅读C声明,因此,请查看我们对tt
所说的内容,并将其与我们如何使用它进行比较。
tt
是变量名。右边是一个右括号,所以我们继续处理当前的范围。我们遇到*
,然后是匹配的paren,然后是静态数组大小,然后是类型。使用顺时针螺旋规则,tt
是指向dd
的数组(大小5)的指针。这意味着,如果你取消引用tt(使用(*tt)
),你得到一个dd[5]
,或者,如果你更愿意这样想(C肯定会这样),那么指向一个块的开头的指针足够大的内存来容纳你的结构。更重要的是,这就是你所说的。 C对指针类型实际上非常挑剔,这就是为什么你的代码编译即使你犯了严重的类型错误。
你的malloc语句是正确的:它正在初始化tt
,其内存位置是操作系统承诺的,有足够的空间容纳你的五个ss
。因为C不会像数组大小边界检查这样愚蠢的事情,所以struct ss
的5元素数组保证是单个struct ss
的五倍大小,所以你实际上可以写了malloc(5 * sizeof(dd))
,但无论哪种写作方式都没问题。
但是,让我们来看看这里发生的事情:
tt[i]->p=malloc(sizeof(int));
糟糕, tt
是指向struct dd
的数组的指针,但您只是将其视为指针数组到struct { {1}}。
你想要的是什么:
dd
tt
i
个元素
dd
你实际得到了什么:
p
i
个元素
dd
的指针,因为C不知道数组和指针之间的区别 dd
当p
为0时,这样可以正常工作,因为数组中的第0个元素和数组本身位于同一位置。 (一个数组没有标题,C _不能理解数组和指针之间的区别,并且允许你互换使用它们,这就是为什么要编译它。)
当i
不为0时,会造成大量内存。现在你正在写任何跟随指针发生的记忆!它实际上是一个指针,但你告诉C它是一个数组,并且它相信你,在它的位置增加了1个元素宽度,并试图做所有这些操作。你准确地使用数组,你应该使用指针,指针应该在你应该使用数组的位置。
你只能写入你为元素0分配的内存。除此之外,你还要写入不相关的内存,而且运气不好(在你的情况下运气不好)让你的程序不能正常崩溃那里。 (如果有的话,你可以更容易地发现这是一个有罪的线。)当你i
你分配的内存时,第一个元素是有效的,其余的是垃圾,你的{{1导致数据结构中有一个有效元素,然后是随机堆垃圾,当你试图取消引用一个指针时会导致崩溃(这只会因为程序没有结束而有效)。
这是访问指针到数组的正确方法:
fwrite
...
此外,您正在分配内存,然后立即忘记您对它的唯一引用,这是一个内存泄漏,因为您通过引用您正在初始化的静态数组来覆盖指针一切都与。请改用:
fread
我强烈建议您完整地学习A Tutorial on Pointers and Arrays。它将帮助您将来避免这类问题。
请注意,在以完全相同的方式打印内容时,您正在正确阅读(*tt)[i].p=malloc(sizeof(int));
。
答案 1 :(得分: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.