C中的读写结构
我有一个结构:C中的读写结构,c,file,C,File,我有一个结构: typedef struct student { char fname[30]; char sname[30]; char tname[30]; Faculty fac; int course; char group[10]; int room; int bad; } Student; 我从文件中读到: Database * dbOpen(char *
typedef struct student
{
char fname[30];
char sname[30];
char tname[30];
Faculty fac;
int course;
char group[10];
int room;
int bad;
} Student;
我从文件中读到:
Database * dbOpen(char *fname)
{
FILE *fp = fopen(fname, "rb");
List *lst, *temp;
Student *std;
Database *db = malloc(sizeof(*db));
if (!fp)
return NULL;
FileNameS = fname;
std = malloc(sizeof(*std));
if (!fread(std, sizeof(*std), 1, fp)) {
db->head = db->tail = NULL;
return db;
}
lst = malloc(sizeof(*lst));
lst->s = std;
lst->prev = NULL;
db->head = lst;
while (!feof(fp)) {
fread(std, sizeof(*std), 1, fp);
temp = malloc(sizeof(*temp));
temp->s = std;
temp->prev = lst;
lst->next = temp;
lst = temp;
}
lst->next = NULL;
db->tail = lst;
fclose(fp);
return db;
}
我有个问题。。。在最后一条记录中,我有一个这样的文件指针:
`fp 0x10311448{{u ptr=0x00344b90"НННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННН土布*
`
我读了最后一张唱片两遍
保存文件代码:
void * dbClose(Database *db)
{
FILE *fp = fopen(FileNameS, "w+b");
List *lst, *temp;
lst = db->head;
while(lst != NULL) {
fwrite(lst->s, sizeof(*(lst->s)), 1, fp);
temp = lst;
lst = lst->next;
free(temp);
}
free(db);
fclose(fp);
}
第一遍还没有挖得太深,我想说你已经在记录的末尾写了一遍。你显示的输出看起来很像调试内存输出,你会看到它在malloc缓冲区后面。也许你的数据库没有完全正确对齐?现在再看一些…第一遍还没有挖得太深,我想说你已经写了传递记录的结尾。您显示的输出看起来非常像在malloc缓冲区后面看到的调试内存输出。可能您的数据库没有完全正确对齐?现在查看更多…需要考虑的几个观察到的问题: (1) 如果您的文件长度(以字节为单位)不是sizeof(Student)的倍数,该怎么办?那么此代码:
while (!feof(fp)) {
fread(std, sizeof(*std), 1, fp);
...
无法将部分结构读入std
指向的内存。std
的内容将被部分填充,并可能在内存中留下未终止的C字符串
您必须检查fread()
的返回值
(2) 这是一个更重要的问题。您正在使用std
分配和指向的内存,尽管您将指针存储在链接列表的每个元素中
似乎您的目的是为每个学生
记录分配新内存。在这种情况下,您将在循环体中调用malloc()
,循环体从文件中读取多条记录
此错误还取决于文件长度--文件必须包含多条记录
(3) 您可以重新组织代码,以便在循环迭代期间也读取第一条记录,以删除不必要的重复代码
(4)您可以考虑使用<代码> CalOrthe()/代码>以确保您已经初始化了
Database * dbOpen(char *fname)
{
FILE *fp = fopen(fname, "rb");
List *lst, *temp;
Student *std;
Database *db = NULL;
if (!fp)
return db;
FileNameS = fname;
db = malloc(sizeof(*db));
db->head = NULL;
lst = NULL;
while (!feof(fp)) {
std = malloc(sizeof(*std));
if (!fread(std, sizeof(*std), 1, fp))
{
free(std);
fprintf(stderr, "Input file concludes in partial record.\n");
break;
}
temp = malloc(sizeof(*temp));
temp->s = std;
temp->prev = lst;
temp->next = NULL;
if (lst == NULL)
db->head = temp;
else
lst->next = temp;
lst = temp;
}
assert(lst->next == NULL ); /* Now performed above by temp->next assignement. */
db->tail = lst;
fclose(fp);
return db;
}
我没有编译和测试上面的代码,但它应该可以正常工作。注意如何在initialize
db->head
(第一次通过循环,lst等于NULL)中添加一个特例,否则前面的列表元素将链接到新添加的元素(稍后的迭代)。当然,我们也应该检查malloc()的返回值,但为了清楚起见,这里省略了这一点。您需要考虑的几个观察到的问题:
(1) 如果您的文件长度(以字节为单位)不是sizeof(Student)的倍数,该怎么办?那么此代码:
while (!feof(fp)) {
fread(std, sizeof(*std), 1, fp);
...
无法将部分结构读入std
指向的内存。std
的内容将被部分填充,并可能在内存中留下未终止的C字符串
您必须检查fread()
的返回值
(2) 这是一个更重要的问题。您正在使用std
分配和指向的内存,尽管您将指针存储在链接列表的每个元素中
似乎您的目的是为每个学生
记录分配新内存。在这种情况下,您将在循环体中调用malloc()
,循环体从文件中读取多条记录
此错误还取决于文件长度--文件必须包含多条记录
(3) 您可以重新组织代码,以便在循环迭代期间也读取第一条记录,以删除不必要的重复代码
(4)您可以考虑使用<代码> CalOrthe()/代码>以确保您已经初始化了
Database * dbOpen(char *fname)
{
FILE *fp = fopen(fname, "rb");
List *lst, *temp;
Student *std;
Database *db = NULL;
if (!fp)
return db;
FileNameS = fname;
db = malloc(sizeof(*db));
db->head = NULL;
lst = NULL;
while (!feof(fp)) {
std = malloc(sizeof(*std));
if (!fread(std, sizeof(*std), 1, fp))
{
free(std);
fprintf(stderr, "Input file concludes in partial record.\n");
break;
}
temp = malloc(sizeof(*temp));
temp->s = std;
temp->prev = lst;
temp->next = NULL;
if (lst == NULL)
db->head = temp;
else
lst->next = temp;
lst = temp;
}
assert(lst->next == NULL ); /* Now performed above by temp->next assignement. */
db->tail = lst;
fclose(fp);
return db;
}
我没有编译和测试上面的代码,但它应该可以正常工作。注意如何在initializedb->head
(第一次通过循环,lst等于NULL)中添加一个特例,否则前面的列表元素将链接到新添加的元素(稍后的迭代)当然,我们还应该检查malloc()的返回值,但为了清楚起见,这里没有检查返回值。在这个循环中:
while (!feof(fp)) {
fread(std, sizeof(*std), 1, fp);
temp = malloc(sizeof(*temp));
temp->s = std;
temp->prev = lst;
lst->next = temp;
lst = temp;
}
您使用的是fread
的结果,而没有检查它是否成功返回。
在假定数据已成功读取之前,应检查feof(fp)或fread的返回值。在此循环中:
while (!feof(fp)) {
fread(std, sizeof(*std), 1, fp);
temp = malloc(sizeof(*temp));
temp->s = std;
temp->prev = lst;
lst->next = temp;
lst = temp;
}
您使用的是fread
的结果,而没有检查它是否成功返回。
在假设数据已成功读取之前,您应该检查feof(fp)
或fread
的返回值。这对我来说很突出:
while (!feof(fp)) {
fread(std, sizeof(*std), 1, fp);
temp = malloc(sizeof(*temp));
temp->s = std;
temp->prev = lst;
lst->next = temp;
lst = temp;
}
您不应使用feof()
作为循环条件;只有在尝试读取文件结尾之后,才会设置文件结尾指示符,因此您的循环将执行太多次。重新构造循环以使用fread()
的返回值,并且仅当fread()时才检查feof()
失败:
while (fread(std, sizeof *std, 1, fp) == 1)
{
temp = malloc(sizeof *temp);
temp->s = std;
...
}
if (feof(fp))
// handle end of file
else
// handle other read error
这对我来说很突出:
while (!feof(fp)) {
fread(std, sizeof(*std), 1, fp);
temp = malloc(sizeof(*temp));
temp->s = std;
temp->prev = lst;
lst->next = temp;
lst = temp;
}
您不应使用feof()
作为循环条件;只有在尝试读取文件结尾之后,才会设置文件结尾指示符,因此您的循环将执行太多次。重新构造循环以使用fread()
的返回值,并且仅当fread()时才检查feof()
失败:
while (fread(std, sizeof *std, 1, fp) == 1)
{
temp = malloc(sizeof *temp);
temp->s = std;
...
}
if (feof(fp))
// handle end of file
else
// handle other read error
这是我喜欢STL容器的众多原因之一。很容易忘记调试列表代码是多么有趣