结构的首地址
您好,我正在致力于基于struct
的项目。我在保存我的结构的第一个地址时遇到问题。问题不在于我的N功能,它工作正常。我的问题是,在我的V函数中,它仅打印我最后的结构列表。我希望它能够从我的结构中打印出我的所有信息,而不仅仅是最后一个。我希望我自己理解的结构的首地址
CODE:
typedef struct stuff {
char signatura[12];
char isbn[15];
char kniha[100];
char autori[100];
int datum;
int preukaz;
struct stuff *p_dalsi;
} STUFF;
STUFF *alokuj(void){
STUFF *p_pom;
p_pom=(STUFF *) malloc (sizeof(STUFF));
return p_pom;
}
void nacitaj(STUFF *p_akt){
FILE *fr;
int pocet_zaznam=0, pocet_enter=0, i;
char c, s[100];
if ((fr = fopen("KNIZNICA.TXT","r")) == NULL){
printf("Zaznamy neboli nacitane\n");
}
while((c=getc(fr))!= EOF) {
if(c=='\n') pocet_enter++;
}
pocet_zaznam=(pocet_enter+1)/7;jeden zaznam ma 7 casti
rewind(fr);i
for (i=1;i<=pocet_zaznam;i++){
fgets(s,100,fr); //vynechanie prveho riadku v subore
fgets(p_akt->signatura,12,fr);
fgets(p_akt->isbn,15,fr);
fgets(p_akt->kniha,100,fr);
fgets(p_akt->autori,100,fr);
fscanf(fr,"%d\n",&p_akt->datum);
fscanf(fr,"%d\n",&p_akt->preukaz);
p_akt->p_dalsi=NULL;
}
printf("Nacitalo sa %d zaznamov\n",pocet_zaznam);
fclose(fr);
}
void vypis(STUFF *p_akt) {
int zaznam_poradie=1;
while(p_akt!=NULL) {
printf("%d.\n",zaznam_poradie);
printf("signatura: %s",p_akt->signatura);
printf("isbn: %s",p_akt->isbn);
printf("kniha: %s",p_akt->kniha);
printf("autori: %s",p_akt->autori);
printf("datum: %d\n",p_akt->datum);
printf("datum: %d\n",p_akt->preukaz);
zaznam_poradie++;
p_akt=p_akt->p_dalsi;
}
}
int main() {
char c;
STUFF *p_prv = NULL;
STUFF *p_akt = NULL;
p_akt = p_prv;
p_prv = (STUFF *)malloc(sizeof(STUFF));
while(c!='K') {
c = getchar();
if(c=='N') {
p_akt = p_prv;
nacitaj(p_akt);
}
if(c=='V') {
p_akt = p_prv;
vypis(p_akt);
}
if(c=='P');
if(c=='Z');
if(c=='H');
if(c=='A');
}
return 0;
}
问题是与你的 'N功能';它不会创建列表,代码也不会调用它。
供给不会编译的代码:
pocet_zaznam=(pocet_enter+1)/7;jeden zaznam ma 7 casti
rewind(fr);i
jeden ... casti
的部分可以认为是没有其注释标记评论。 i
似乎只是无关紧要的。分析可以忽略这些问题。
但是,看起来该函数读取文件,计算其中的换行符的数量,然后重新读取该文件以加载数据。尽管如此,它仍然在写同一个单一结构,并且不会尝试分配新结构或将当前结构与前一结构连接起来。请注意,您的分配功能alokuj()
未在您显示的代码中调用。
当最后调用'V-函数'时,唯一需要处理的数据是最后一个被读取的条目,因为之前的条目已被覆盖。
您需要重做代码,为每个要读取的项目分配一个新的结构,将它们全部收集到一个列表中,并且(可能)将列表头部返回到调用代码。
你也应该是错误检查功能,可能会失败。你确实检查fopen()
,但是你继续使用返回值,即使它是NULL - 你不应该,你应该将错误报告给标准错误,而不是标准输出。你应该检查内存分配;你应该检查fgets()
。当然,当文件被打开时,它包含一定数量的行;但是在重新读取文件时可能会被截断,所以您仍然需要检查。您可能还需要从字符串中删除换行符(fgets()
在字符串中包含换行符)。
#include <stdlib.h>
#include <stdio.h>
typedef struct stuff
{
char signatura[12];
char isbn[15];
char kniha[100];
char autori[100];
int datum;
int preukaz;
struct stuff *p_dalsi;
} STUFF;
static STUFF *alokuj(void)
{
STUFF *p_pom = (STUFF *) malloc (sizeof(STUFF));
if (p_pom == 0)
{
fprintf(stderr, "Out of memory\n");
exit(1);
}
return p_pom;
}
static void vypis(STUFF *p_akt)
{
int zaznam_poradie=1;
while (p_akt != NULL)
{
printf("%d.\n", zaznam_poradie);
printf("signatura: %s", p_akt->signatura);
printf("isbn: %s", p_akt->isbn);
printf("kniha: %s", p_akt->kniha);
printf("autori: %s", p_akt->autori);
printf("datum: %d\n", p_akt->datum);
printf("datum: %d\n", p_akt->preukaz);
p_akt=p_akt->p_dalsi;
zaznam_poradie++;
}
}
static STUFF *nacitaj(void)
{
FILE *fr;
int pocet_zaznam = 0;
int pocet_enter = 0;
int i;
char s[100];
int c;
if ((fr = fopen("KNIZNICA.TXT", "r")) == NULL)
{
fprintf(stderr, "Zaznamy neboli nacitane\n");
exit(1);
}
while ((c = getc(fr)) != EOF)
{
if (c == '\n')
pocet_enter++;
}
pocet_zaznam = (pocet_enter+1)/7;
rewind(fr);
STUFF *p_head = 0;
STUFF *p_last = 0;
for (i = 1; i <= pocet_zaznam; i++)
{
STUFF *p_akt = alokuj();
if (fgets(s, 100, fr) == 0 || // 100 should be sizeof(s) ... etc
fgets(p_akt->signatura, 12, fr) == 0 ||
fgets(p_akt->isbn, 15, fr) == 0 ||
fgets(p_akt->kniha, 100, fr) == 0 ||
fgets(p_akt->autori, 100, fr) == 0 ||
fscanf(fr, "%d\n", &p_akt->datum) != 1 ||
fscanf(fr, "%d\n", &p_akt->preukaz) != 1)
// "%d\n" would be bad for interactive I/O; OK for file I/O
{
fprintf(stderr, "Data format error\n");
exit(1);
}
p_akt->p_dalsi = NULL;
//printf("Read entry %d:\n", i);
//vypis(p_akt);
if (p_head == 0)
p_head = p_akt;
else
p_last->p_dalsi = p_akt;
p_last = p_akt;
}
printf("Nacitalo sa %d zaznamov\n", pocet_zaznam);
fclose(fr);
return p_head;
}
int main(void)
{
int c;
STUFF *p_akt = NULL;
while (c!='K')
{
c = getchar();
if (c == EOF)
break;
else if (c == 'N')
p_akt = nacitaj();
else if (c == 'V')
vypis(p_akt);
else if (c != '\n')
fprintf(stderr, "Unrecognized commmand: %c\n", c);
}
return 0;
}
数据文件KNIZNICA.TXT
Rubbish1
signature1
Writing C Programs on Stack Overflow
Jonathan Leffler
20120505
1234
Rubbish2
signature2
212
Rewriting C Programs on Stack Overflow
Leffler, Jonathan
20130505
2234
实施例运行(程序名ak
):
$ ./ak
N
Nacitalo sa 2 zaznamov
V
1.
signatura: signature1
isbn:
kniha: Writing C Programs on Stack Overflow
autori: Jonathan Leffler
datum: 20120505
datum: 1234
2.
signatura: signature2
isbn:212
kniha: Rewriting C Programs on Stack Overflow
autori: Leffler, Jonathan
datum: 20130505
datum: 2234
$
我通常在for
循环使用for (i = 0; i < N; i++)
- 它是比for (i = 1; i <= N; i++)
更习惯C语言。
gcc -O3 -g -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition ak.c -o ak
因为我编译这样的,我不认为在malloc()
投是一个问题:因为我用坚持功能编译标志被定义或使用之前所声明的功能是由静态的。那些抱怨malloc()
上的演员主要关注'如果malloc()
未被声明会发生什么情况',但是在我编译时这已经是一个警告(我有效地将其视为错误;我会添加-Werror
以确保它是在形式上是一个错误),所以这对我来说不是问题。 (所显示的代码也可以编译为一个有效的C++程序,因为转换是存在的;如果转换丢失了,它将不是一个有效的C++程序,它不是一个好的C++程序;它是一个C程序。我使用V函数来调试N函数,我将V函数移到了N函数之上。
你SIR,你应该得到这个职位的奖章。我是一个真正想学习东西的人,最好的方法就是学习我自己的错误。你向他们展示了几个并重新编写代码,现在它可以工作。最后30分钟,我正在分析你在这里告诉我的情况,现在全部都变得非常合理!我很高兴,总有像你这样的人不仅能够帮助,而且还能解释!谢谢你,先生! – Toesmash 2013-05-05 19:34:46
鉴于有一个链表,你真的不需要重读这个文件;您可以阅读条目,直到遇到错误或EOF。我没有解决这个问题。如果你确实解决了这个问题,那么可以从键盘读取数据,而不是固定文件。我仍然会做出很多改变,但这似乎是使代码合理可靠以及可以做什么之间的必要平衡。永远不要满意您的代码为'完美'。但是,通常会有一个点达到“足够好”的地步,那就是停止修补的时候了。 – 2013-05-05 19:48:44
1.您不需要在C程序中投射'malloc'的返回值。 2.缩进和格式很重要。 – 2013-05-05 14:48:24
“我的问题是,在我的V函数中,它仅打印我最后的结构列表。”这意味着你将它传递给列表中最后一个元素的指针。没有看到更多的代码,更多的我不能说。 – 2013-05-05 14:50:53
这是捷克?还是斯洛伐克? – 2013-05-05 14:56:38