我正在尝试从C中的二进制文件中编写和读取链接列表。 我的目标是为护理院保存和加载居民数据(实际上,我是护士),以便通过资源利用组对每个居民进行分类。我已经使用一系列结构为固定数量的居民(32,即设施的容量)做了这个,但现在我需要为一组可变的居民做这样的事情,以便进行统计研究。 显然,对于第一次尝试,我将结构简化为最小,因为实际结构包含109个数据。
我非常接近解决方案,但有些东西不起作用,也就是说,保存列表的每个元素都替换为void one.This代码应从二进制文件中读取列表,在终端上显示,添加一个新元素,保存列表。当然,每个程序都应该放在一个函数中。
GC
答案 0 :(得分:2)
你是如此接近,我甚至不确定失败的真正原因是什么,因为,对于第一次切割,我只是应用了[大部分]其他人建议的修复并得到了一个有效的程序。 / p>
虽然它有效,但我发现你提前做了一个"提前一步"当你扩展程序做其他事情时,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
为空但已链接到列表中。松散地,一个&#34;僵尸&#34;记录,如果你愿意。
也就是说,该列表在之前链接了一个条目它已被填写并验证。换句话说,在读取循环之后,但在提示用户输入新条目之前,列表可能被视为格式错误(即[小]违反&#34;合同编程&#34;或者&#34;按合同设计&#34;原则)。
第二个程序中的功能拆分只是为了强调这一点。特别是,通过将读取循环移动到单独的函数,它说明/强制执行按合同设计。
也就是说,在进入时,列表是完整的并且格式良好[尽管是空的]。返回时,它为空[如果输入文件不存在]或者其中只有格式良好/完整的记录。
在第二个程序中,部分/格式错误的条目永远不会链接。add_to_list
总是最后完成[仅限整个/完整记录]。
因此,对于read_archive
和add_new_entries
,当它们被调用时,它们都被给予一个完整/完整的列表,其中只包含有效的完整形式的记录。这是&#34;合同&#34; 他们。
并履行他们的合同&#34;这些函数必须保持相同的方式,在退出时保持列表的完整性。这就是功能&#39; &#34;合同&#34;对外界
更新#2:
请原谅我的OT,但是你能否建议我使用一个适用于Debian / GNU Linux的C-C ++的好IDE?
我可能不是最好的人就此建议你,因为我没有使用它。我在他们存在之前很早就写了C,所以我开发了自己的工具套件,它比我见过的任何IDE都强大得多。而且,当我看着它们时,我找不到一种方法来对这两者进行网格化。
我在家里使用Code :: Blocks,但不幸的是,所谓的夜间构建是错误的并经常崩溃
如果您在家中使用代码块,但每晚构建有问题,也许简单的解决方案是将您的更新切换到&#34;稳定&#34;树,如果可能的话。这可能是最好的答案&#34;。
(代码完成实用程序非常有用,但我不能输入str ...,否则它会冻结),这非常令人沮丧!
也许您可以查看错误数据库,看看您遇到的问题是否已知错误报告。如果没有,你可以/应该提交一个。
我安装了codeblocks
。它看起来干净简单。我还安装了eclipse
并查看了kdevelop
。从几个网页中,eclipse获得高分,netbeans
接近第二
我尝试在源文件上使用它们,我躺在那里用Makefile构建。 codeblocks非常直观,我可以快速完成。我和其他人一起遇到了更多麻烦。 eclipse最初由IBM设计用于内部使用,然后作为公共服务发布。它得到了很好的支持和成熟。
我一直在运行没有 CDT的eclipse ,但是一旦我添加了它,eclipse
得到了我的投票,因为它似乎有足够的功能来控制我所有的东西在下面抱怨; - )
IDE是一种个人选择[除非贵公司要求],所以你应该使用你喜欢的东西。换句话说,尝试一下,看看他们有什么功能以及它们的工作原理。这是一个列出一些页面的页面:https://en.wikipedia.org/wiki/Comparison_of_integrated_development_environments
选择IDE时,您必须查看&#34;最常用的&#34;特征。您最常做的事情是在源文件中滚动。因此,编辑器应支持箭头键的hjkl
别名,如vi
。不得不将你的右手移到箭头键和后面,这会使事情变得非常缓慢,以至于它不会起作用。
eclipse使用gvim
[图形vim
],所以这是一个加号。
我不是一个使用简单的所见即所得编辑器窗格进行编辑的粉丝,该窗格只有粗略的搜索/替换功能。同样地,vim
只需键入/
即可进行正则表达式搜索,因此,最常见的操作是&#34;触手可及&#34;
我没有使用[或想要]自动完成功能。当我尝试过它们时,它们经常会出错,并且需要更长时间才能完成它们所做的事情。我打字速度非常快。
我还关闭了源的语法高亮和着色。在输入源代码时,由于编辑器认为我正在打字,所以输入的每个字符的颜色都会发生变化(例如我输入了一条评论,但它认为它是&#39;我的代码,等等。我发现这会分散注意力。
另外,在查看最终结果时,我发现彩色结果太忙了#34; (即我需要过滤的更多信息),而不是帮助我看到我需要看到的东西。
我非常坚持缩进,用空行分解长代码块以提高可读性。当然还有好的评论。对我来说,这些比着色要重要得多。我有一个缩进的自定义工具[你可能还记得,当我发布上面的代码时,它被重新缩进,因为我在发布之前通过我的工具运行它。
另一个功能是图形调试器。它是全功能的吗?例如,ddd
是围绕[非常强大的] gdb
的图形包装器。 ddd
为常见事物提供了图形包装器和窗口,但仍允许gdb
提示符的直接文本窗口,因此您可以手动键入更高级的命令(例如watch symbol
)。
IDE是否可扩展?你能加点插件吗?你能轻松添加/创建自己的吗?
IDE使用什么源代码控制系统?多年来我一直使用很多,现在,我已在git
完全销售。因此,如果IDE不支持git
,那么它就不是首发。
应该注意的是,git
具有所以许多功能,而不是不包含在GUI中。因此,真正强大的东西在终端窗口中使用命令行工具。
我的IDE?几个xterm
窗口,vi
,git
和我的工具套件[目前有250,000行perl
脚本;-)]
IDE会强迫您按照自己的方式行事吗?将配置等导入/导出到其他外部工具和IDE有多容易?
我有一个非常强大的自己设计的构建脚本。所以,当我点击&#34; build&#34;时,我想要IDE。按钮不执行通常的操作,但将控制权交给我的构建脚本。同样,对于IDE必须提供的任何其他操作。
IDE是否可移植并可在所有主要平台上使用:Linux,OSX和Windows?在过去,这是我回避IDE的另一个原因。它们只能在一个平台上使用。或者,由于我正在进行咨询工作,因此我会进入一个不允许通过[sysadmin]策略安装/使用IDE的环境。