gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-03 02:54:51 25 4
gpt4 key购买 nike

我正在尝试从 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;
}

更新:

I was still trying to figure out the reason of my failure



我没有调试/单步执行您的原始代码,因为我认为您的链表逻辑需要修复,我想快速解决这个问题。但是,经过我的审查,逻辑很好。根据我的最佳猜测分析,可能的故障是 feof我已经更改为长度检查 fread .

Of course I was going to organize better the program using functions



我以为你会的。第二个程序中的拆分更像是一种澄清和说明原则的教学工具,而不是对模块化的批评。

在您的原始代码中,您必须添加一条新记录,因为 osp为空但已链接到列表中。松散地,一个“僵尸”记录,如果你愿意的话。

也就是说,该列表在填写和验证之前链接了一个条目。换句话说,在读取循环之后,但在用户被提示输入新条目之前,该列表可能被视为格式错误(即 [小] 违反“契约(Contract)编程”或“契约(Contract)设计”原则)。

第二个程序中的功能拆分只是为了强调这一点。特别是,通过将读取循环移动到一个单独的功能,它说明/强制执行契约(Contract)设计。

也就是说,在输入时,列表是完整且格式良好的 [尽管是空的]。返回时,它要么是空的[如果输入文件不存在],要么其中只有格式良好/完整的记录。

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

因此,对于 read_archiveadd_new_entries ,当它们被调用时,它们都会得到一个完整/完整的列表,其中只有有效的、完全形成的记录。这就是他们的“契约(Contract)”。

并且为了履行他们的“契约(Contract)”部分,这些功能必须以相同的方式保持不变,在退出时保持列表的完整性。这就是函数与外界的“契约”

更新 #2:

excuse me for the OT, but could you suggest to me a good IDE for C - C++ that works well with Debian/GNU Linux ?



我可能不是就此向您提供建议的最佳人选,因为我不使用它。我在 C 出现之前很久就在编写它们,所以我开发了自己的工具套件,它比我见过的任何 IDE 都强大得多。此外,当我查看它们时,我永远找不到将两者结合起来的方法。

I'm at home with Code::Blocks, but unfortunately the so called nightly build is buggy and crashes very often



如果您在家中有代码块,但每晚构建有问题,那么简单的解决方案可能是将更新切换到“稳定”树,如果可能的话。这可能是最好的“简短回答”。

(the code completion utility is very useful but I must not type str..., otherwise it freezes), and that's very frustrating!



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

我安装了 codeblocks .它看起来干净简单。我也安装了 eclipse并查看了 kdevelop .从几个网页来看,eclipse 获得高分, netbeans紧接着

我尝试在我使用 Makefile 构建的源文件中使用它们。代码块足够直观,我可以快速完成。我和其他人有更多的麻烦。 eclipse 最初由 IBM 设计供内部使用,然后作为公共(public)服务发布。它得到了很好的支持和成熟。

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

IDE 是一种个人选择[除非您的公司要求这样做],因此您应该使用自己喜欢的。换句话说,尝试一些,看看它们有什么功能以及它们是如何工作的。这是一个列出了一些的页面: https://en.wikipedia.org/wiki/Comparison_of_integrated_development_environments

在选择 IDE 时,您必须查看“最常用”的功能。您最常做的事情是在源文件中滚动。所以,编辑器应该支持 hjkl箭头键的别名,如 vi做。必须将右手移到箭头键上并返回会减慢速度,以至于无法启动。

eclipse 使用 gvim [图形 vim ],所以这是一个加号。

我不喜欢使用一些简单的 WYSIWYG 编辑器 Pane 进行编辑,该 Pane 仅具有粗略的搜索/替换功能。同样, vim只需键入 / 即可允许正则表达式搜索,所以再一次,最常见的操作是“触手可及”

我不使用 [也不想要] 自动完成功能。当我尝试过它们时,它们经常出错,并且需要更长的时间来回退他们所做的事情。我是一个非常快的打字员。

我还关闭了源代码的语法高亮和着色。输入源代码时,由于编辑器认为我正在输入的内容(例如,我正在输入注释,但它认为是代码等),因此输入的每个字符的颜色都会发生变化,我发现这会分散注意力.

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

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

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

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

IDE 使用什么源代码控制系统?多年来我已经使用了很多,现在,我完全在 git 上出售了。 .因此,如果 IDE 不支持 git ,这是一个非启动器。

需要注意的是 git具有如此多的功能,以至于它们无法包含在 GUI 中。所以,真正强大的东西在终端窗口中使用命令行工具。

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

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

IDE 是否可移植并可在所有主要平台上使用:linux、OSX 和 Windows?过去,这是我回避 IDE 的另一个原因。它们只能在一个平台上使用。或者,因为我在做咨询工作,我会进入一个环境,由于 [sysadmin] 政策,不允许安装/使用 IDE。

关于c - 将链表保存并加载到二进制文件 (C),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37821720/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com