Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/file/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C中的读写结构_C_File - Fatal编程技术网

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()/代码>以确保您已经初始化了学生< /C> >的所有记录。

像这样:

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()/代码>以确保您已经初始化了学生< /C> >的所有记录。

像这样:

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()的返回值,但为了清楚起见,这里没有检查返回值。

在这个循环中:

    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容器的众多原因之一。很容易忘记调试列表代码是多么有趣