我正在尝试从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_archive
和add_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
是[非常强大]周围的图形包装gdb
。ddd
提供图形化包装器和用于常见事物的窗口,但仍允许为gdb
提示提供直接文本窗口,因此您可以手动键入更高级的命令(例如watch symbol
)。
IDE是可扩展的吗?您可以添加插件吗?您可以轻松添加/创建自己的吗?
IDE使用哪种源代码控制系统?多年来,我已经用了很多年,现在已完全售出git
。因此,如果IDE不支持git
,那就不是启动器了。
应该注意的是,git
具有如此多的功能,使其无法包含在GUI中。因此,真正强大的功能是在终端窗口中使用命令行工具。
我的IDE?几个xterm
Windows,vi
和git
,以及我的工具套件[当前为250,000行perl
脚本;-)] IDE是否会强迫您按照自己的方式做事?将配置等导入/导出到其他外部工具和IDE有多容易?
我有自己设计的非常强大的构建脚本。因此,我希望IDE在单击“构建”按钮时不执行其通常会执行的操作,而是将控制权移交给我的构建脚本。同样,IDE必须提供其他任何操作。
IDE是否可移植且可在所有主要平台上使用:Linux,OSX和Windows?过去,这是我远离IDE的另一个原因。它们仅在一个平台上可用。或者,由于我从事咨询工作,由于[sysadmin]策略,我将进入不允许安装/使用IDE的环境。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句