将链接列表保存并加载到二进制文件(C)

用户名

我正在尝试从C中的二进制文件写入和读取链接列表。我的目的是保存和加载疗养院的居民数据(实际上,我是一名护士),以便通过资源利用对每个居民进行分类组。我已经使用一组结构对固定数量的居民(32个设施的容量)进行了此操作,但是现在我需要对一组可变的居民进行此操作,以便进行统计研究。显然,对于第一次尝试,我将结构简化到最小,因为实际结构包含109个数据。

我非常接近解决方案,但是有些方法行不通,也就是说,已保存列表的每个元素都用一个空格代替。这段代码应该从二进制文件中读取列表,在终端上显示出来,然后添加一个新元素,保存列表。当然,每个过程都应该放在一个函数中。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ncurses.h>

struct pat
{
    char surn [16];
    char name [16];
    struct pat *next;
};

static FILE *h;
static struct pat *osp;
static struct pat *first;

struct pat *make_structure (void);

int main()
{
    initscr();
    raw();
    keypad (stdscr, TRUE);
    noecho();

    clear();

    osp=make_structure();
    first=osp;

    h=fopen ("archivio","r");

    if (h==NULL)
        printw ("Archivio inesistente\n");
    else
    {
        while (!feof(h))
        {
            printw ("Lungh. nome = %d\n",sizeof osp->name);
            fread (osp->surn,sizeof osp->surn,1,h);
            fread (osp->name,sizeof osp->name,1,h);
            printw ("Cognome: %s\tNome: %s\n",osp->surn,osp->name);
            osp->next=make_structure();
            osp=osp->next;
        }
    }

    getch();

    echo();
    printw ("Surname: ");
    scanw ("%s",osp->surn);
    printw ("\nName: ");
    scanw ("%s",osp->name);

    noecho();

    osp=first;

    h=fopen ("archivio","w");

    while (osp != NULL)
    {
        fwrite (osp->surn,sizeof osp->surn,1,h);
        fwrite (osp->name,sizeof osp->name,1,h);
        osp=osp->next;
    }

    return 0;
}

struct pat *make_structure(void)
{
    struct pat *a;
    a = (struct pat *)malloc(sizeof(struct pat));
    return (a);
}
克雷格·埃斯蒂

您是如此亲密,我什至不知道真正的失败原因是什么,因为对于第一次剪切,我只是应用了其他人建议的大多数修复程序并获得了有效的程序。

尽管有效,但我发现make_structure将程序扩展为执行其他操作时,执行“向前一个”调用的方式不太灵活。

例如,如果您决定添加新记录,而不是添加新记录,而是对现有记录进行一些统计或操作,则将有一个悬挂的“鬼”记录

因此,我创建了该程序的第二个版本,该版本具有更多的隔离性和通用性。


这是最少更改的版本[请原谅免费的样式清理]:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ncurses.h>

struct pat {
    char surn[16];
    char name[16];
    struct pat *next;
};

static FILE *h;
static struct pat *osp;
static struct pat *first;

struct pat *make_structure(void);

int
main()
{
    int rlen;

    initscr();
    raw();
    keypad(stdscr, TRUE);
    noecho();

    clear();

    osp = make_structure();
    first = osp;

    h = fopen("archivio", "r");

    if (h == NULL)
        printw("Archivio inesistente\n");
    else {
        while (1) {
            printw("Lungh. nome = %d\n", sizeof osp->name);

            // leave early on EOF or badly formed entry
            rlen = fread(osp->surn, sizeof osp->surn, 1, h);
            if (rlen != 1)
                break;

            // leave early on EOF or badly formed entry
            fread(osp->name, sizeof osp->name, 1, h);
            if (rlen != 1)
                break;

            printw("Cognome: %s\tNome: %s\n", osp->surn, osp->name);

            osp->next = make_structure();
            osp = osp->next;
        }
        fclose(h);
    }

    // NOTE: this just chews the first character (debug, I suppose?)
#if 0
    getch();
#endif

    // add new element
    echo();
    printw("Surname: ");
    scanw("%15s", osp->surn);
    printw("Name: ");
    scanw("%15s", osp->name);

    noecho();

    h = fopen("archivio", "w");

    osp = first;
    while (osp != NULL) {
        fwrite(osp->surn, sizeof osp->surn, 1, h);
        fwrite(osp->name, sizeof osp->name, 1, h);
        osp = osp->next;
    }

    fclose(h);

    return 0;
}

struct pat *
make_structure(void)
{
    struct pat *a;

    a = malloc(sizeof(struct pat));

    // NOTE: do this for good measure
    a->next = NULL;

    return (a);
}

这是更通用的版本,当您扩展程序的功能时,可能会给您一些想法:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ncurses.h>

struct pat {
    char surn[16];
    char name[16];
    struct pat *next;
};

static FILE *h;
static struct pat *osp;
static struct pat *first;
static struct pat *prev;

void read_archive(const char *file);
void add_new_elements(void);
void write_archive(const char *file);
struct pat *make_structure(void);
void add_to_list(struct pat *pat);

int
main()
{

    initscr();
    raw();
    keypad(stdscr, TRUE);
    noecho();

    clear();

    read_archive("archivio");

    // NOTE: this just chews the first character (debug, I suppose?)
#if 0
    getch();
#endif

    // NOTE: instead of just automatically adding new elements, this might
    // be replaced with a menu, such as:
    //   Enter Operation:
    //     (1) Add new names
    //     (2) Calculate statistics
    //     (3) Backup database
    add_new_elements();

    write_archive("archivio");

    return 0;
}

// read_archive -- read in archive
void
read_archive(const char *file)
{
    int rlen;

    h = fopen(file, "r");

    if (h == NULL)
        printw("Archivio inesistente\n");

    else {
        while (1) {
            osp = make_structure();

            // leave early on EOF or badly formed entry
            rlen = fread(osp->surn, sizeof osp->surn, 1, h);
            if (rlen != 1)
                break;

            // leave early on EOF or badly formed entry
            fread(osp->name, sizeof osp->name, 1, h);
            if (rlen != 1)
                break;

            printw("Cognome: %s\tNome: %s\n", osp->surn, osp->name);

            add_to_list(osp);
        }

        // NOTE: this is _always_ for EOF or bad entry, so free it
        free(osp);

        fclose(h);
    }
}

// add_new_elements -- prompt for new elements
void
add_new_elements(void)
{

    echo();
    while (1) {
        osp = make_structure();

        printw("Surname: ");
        osp->surn[0] = 0;
        scanw("%15s", osp->surn);
        if (osp->surn[0] == 0)
            break;

        printw("Name: ");
        osp->name[0] = 0;
        scanw("%15s", osp->name);
        if (osp->name[0] == 0)
            break;

        add_to_list(osp);
    }
    noecho();

    free(osp);
}

// write_archive -- write out archive
void
write_archive(const char *file)
{

    h = fopen(file, "w");

    for (osp = first;  osp != NULL;  osp = osp->next) {
        fwrite(osp->surn, sizeof osp->surn, 1, h);
        fwrite(osp->name, sizeof osp->name, 1, h);
    }

    fclose(h);
}

struct pat *
make_structure(void)
{
    struct pat *a;

    a = malloc(sizeof(struct pat));

    // NOTE: do this for good measure
    a->next = NULL;

    return (a);
}

void
add_to_list(struct pat *pat)
{

    if (first == NULL)
        first = pat;
    else
        prev->next = pat;

    prev = pat;
}

更新:

我仍在尝试找出失败的原因

我没有调试/单步执行您的原始代码,因为我认为您的链表逻辑需要修复,因此我想尽快解决。但是,在我查看它之后,逻辑就很好了。根据我的最佳猜测分析,可能的故障是feof我已经更改为长度检查的原因fread

当然,我打算使用函数更好地组织程序

我以为你会的。第二个程序中的拆分更多地是一种用于阐明和说明原理的教学工具,而不是对模块化的批评。

在原始代码中,您必须添加新记录,因为它osp为空,但已链接到列表中。如果可以的话,宽松地记录一张“僵尸”唱片。

也就是说,列表在填写和验证之前已经链接了一个条目换句话说,在读取循环之后,但在提示用户输入新条目之前,该列表可能被认为格式不正确(即“违反”合同编程”或“按合同设计”原则)。

第二个程序中的功能拆分只是为了强调这一点。特别是,通过将读取循环移动到单独的功能,可以按合同说明/执行按合同设计。

即,在输入时,该列表是完整且格式正确的(尽管是空的)。返回时,它要么是空[如果输入文件确实存在]或只阱,形成在它/完整的记录。

在第二个程序中,永远不会链接部分/格式错误的条目add_to_list总是在最后完成[仅对于完整/完整记录]。

因此,对于read_archiveadd_new_entries,当它们被调用时,它们都被赋予一个完整/完整的列表,其中仅包含有效的,格式完整的记录。那是对他们的“合同”

为了履行“合同”的职责,这些功能必须以相同的方式处理,在退出时保持列表的完整性。那就是功能与外界的“契约”


更新#2:

对不起,我是OT,但是您能为我推荐一个与Debian / GNU Linux兼容的C-C ++ IDE吗?

我可能不是最好的人,因为我不使用它。我在C语言存在之前就已经在写它了,所以我开发了自己的工具套件,它比我见过的任何IDE都要强大。另外,当我查看它们时,我永远找不到找到两者的网格的方法。

我在家里使用Code :: Blocks,但是不幸的是,所谓的每晚构建是错误的,并且经常崩溃

如果您在家中使用代码块,但是夜间构建存在错误,那么可能的话,简单的解决方案是将更新切换到“稳定”树。那可能是最好的“简短答案”。

(代码完成实用程序非常有用,但我不能输入str ...,否则它将冻结),这非常令人沮丧!

也许您可以检查错误数据库,看看您遇到的问题是否是已知的错误报告。如果没有,您可以/应该提交一份。


我安装了codeblocks看起来很干净也很简单。我也安装eclipse了一下kdevelop在几个网页上,日食获得高分,netbeans紧随其后

我试图在我用Makefile构建的源文件中使用它们。代码块非常直观,我可以快速进行。我和其他人有更多麻烦。eclipse最初是由IBM设计供内部使用的,然后作为公共服务发布。它得到了良好的支持并且成熟。

我一直在没有CDT的情况下运行eclipse ,但是一旦添加了它,eclipse我就可以投票,因为它似乎具有足够的功能来控制我下面将要讲到的所有内容;-)

IDE是一种个人选择(除非您的公司强制执行),所以您应该使用自己喜欢的东西。换句话说,尝试一些,看看它们具有什么功能以及它们如何工作。这是列出一些内容的页面:https : //en.wikipedia.org/wiki/Comparison_of_integrated_development_environments

选择IDE时,您必须查看“最常用”功能。您最常做的事情是在源文件中滚动。因此,编辑器应该hjkl像箭头一样支持箭头键别名vi不得不将右手移到箭头键上并向后退,这会使事情放慢速度,以至于无法启动。

eclipse使用gvim[graphical vim],所以加号。

喜欢使用某些仅具有粗略搜索/替换功能的简单WYSIWYG编辑器窗格进行编辑。同样,vim只需键入即可进行正则表达式搜索/,因此,最常见的操作“唾手可得”

我不使用[也不想要]自动补全功能。当我尝试过它们时,它们经常会出错,并且要花更多的时间来退回完成的工作。我是一个非常快的打字员。

我还关闭了语法高亮显示和源代码着色。输入源代码时,由于编辑者认为我正在键入的内容(例如,我正在键入注释,但它认为是代码等),颜色几乎随输入的每个字符而改变。我发现这会分散注意力。

另外,在查看最终结果时,我发现着色结果“太忙”(即我必须过滤的更多信息),而不是帮助我看到需要看的东西。

我相当坚持缩进,用空行分割长代码块以提高可读性。当然,还有很好的评论。对我来说,这些远比着色重要。我有一个用于缩进的自定义工具[您可能还记得,当我在上面的代码中发布代码时,它已经缩进了代码,因为我在发布代码之前先通过工具进行了缩进。

另一个功能是图形调试器。它功能齐全吗?例如,ddd是[非常强大]周围的图形包装gdbddd提供图形化包装器和用于常见事物的窗口,但仍允许为gdb提示提供直接文本窗口,因此您可以手动键入更高级的命令(例如watch symbol)。

IDE是可扩展的吗?您可以添加插件吗?您可以轻松添加/创建自己的吗?

IDE使用哪种源代码控制系统?多年来,我已经用了很多年,现在已完全售出git因此,如果IDE不支持git,那就不是启动器了。

应该注意的是,git具有如此多的功能,使其无法包含在GUI中。因此,真正强大的功能是在终端窗口中使用命令行工具。

我的IDE?几个xtermWindows,vigit,以及我的工具套件[当前为250,000行perl脚本;-)] IDE是否会强迫您按照自己的方式做事?将配置等导入/导出到其他外部工具和IDE有多容易?

我有自己设计的非常强大的构建脚本。因此,我希望IDE在单击“构建”按钮时执行其通常会执行的操作,而是将控制权移交给我的构建脚本。同样,IDE必须提供其他任何操作。

IDE是否可移植且可在所有主要平台上使用:Linux,OSX和Windows?过去,这是我远离IDE的另一个原因。它们仅在一个平台上可用。或者,由于我从事咨询工作,由于[sysadmin]策略,我将进入不允许安装/使用IDE的环境。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

将动态加载的二进制文件静态链接为二进制文件

将二进制数据加载到 NumPy 数组

将二进制代码加载到硬件

将二进制文件中的数据读取到C中的链接列表中(访问冲突读取位置)

Java IO,加载和保存二进制文件

二进制文件-obj(game)保存并加载obj

将场景中的所有 InputField 文本保存到一个二进制文件中并将它们加载到 Unity

如何在Qt中使用QDataStream将自定义结构保存/加载到二进制文件中?

将Fortran程序与任意二进制文件链接

将ELF二进制文件与AC程序链接

将类对象保存到二进制文件

将二进制信息保存到文件

OS X:将二进制文件加载到内存时,不执行写入系统调用

在C ++中,将大型二进制文件(1GB-4GB)加载到内存的最快方法是什么?

c-加载原始二进制文件

将库链接到 C++ 中的 linux 二进制文件

C ++将二进制文件写入文件

C#:在二进制文件中读写列表

Unity - 如何保存和加载列表(二进制保存和加载)

将黑白图像加载到二进制数组中

将核心数据二进制图像数据加载到 UIIMage

将大量的二进制数据加载到RAM中

AS3:将图像二进制XML加载到Flash

将二进制文件读入int数组C ++

从后端将二进制数据下载到前端文件

使用javascript将二进制数据下载到文件中

将.msg附件下载到二进制数组

将数字列表保存到(二进制)文件中,每个数字都定义了位数

搜索二进制文件C ++