【问题标题】:First address of struct结构的首地址
【发布时间】:2013-05-05 14:46:00
【问题描述】:

您好,我正在开发一个基于 struct 的项目。我在保存结构的第一个地址时遇到问题。问题不在于我的 N 函数,它工作正常。我的问题是,在我的 V 函数中,它只打印我的最后一个结构列表。我希望它打印我的结构中的所有信息,而不仅仅是最后一个。我希望我能让自己被理解

代码:

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;
}

【问题讨论】:

  • 1.您不需要在 C 程序中强制转换 malloc 的返回值。 2. 缩进和格式很重要。
  • “我的问题是,在我的 V 函数中,它只打印最后一个结构列表。”这意味着您将指针传递给列表中的最后一个元素。没有看到更多的代码,我不能说更多。
  • 这是捷克语吗?还是斯洛伐克人?
  • 我完成了上面的代码。我只是不明白为什么我的 V 函数 printfs 只有 1(最后一个)我的结构元素。有任何想法吗 ?还有它的斯洛伐克语:)
  • 注意getchar返回int,因此c必须声明为int

标签: c memory struct


【解决方案1】:

问题在于您的“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
0123456789212
Writing C Programs on Stack Overflow
Jonathan Leffler
20120505
1234
Rubbish2
signature2
9876543210212
Rewriting C Programs on Stack Overflow
Leffler, Jonathan
20130505
2234

示例运行(程序名ak):

$ ./ak
N
Nacitalo sa 2 zaznamov
V
1.
signatura: signature1
isbn: 0123456789212
kniha: Writing C Programs on Stack Overflow
autori: Jonathan Leffler
datum: 20120505
datum: 1234
2.
signatura: signature2
isbn: 9876543210212
kniha: Rewriting C Programs on Stack Overflow
autori: Leffler, Jonathan
datum: 20130505
datum: 2234
$

我通常会在for 循环中使用for (i = 0; i &lt; N; i++) — 它比for (i = 1; i &lt;= N; i++) 更符合C 语言习惯。这些函数是静态的,因为我使用了坚持在定义或使用函数之前声明函数的编译标志:

gcc -O3 -g -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition ak.c -o ak

因为我是这样编译的,所以我认为malloc() 的演员表不是问题。那些在malloc() 上抱怨演员表的人主要关心“如果未声明malloc() 会发生什么”,但这已经是我编译时的警告(我实际上将其视为错误;我会添加@ 987654339@ 以确保它正式错误),所以这对我来说不是问题。 (显示的代码也可以编译为有效的 C++ 程序,因为存在转换;如果缺少转换,它就不是有效的 C++ 程序。它不是一个好的 C++ 程序;它是一个 C 程序。)我用V函数调试N函数,我把V函数移到了N函数上面。

【讨论】:

  • 先生,您应该为这篇文章获得奖章。我是一个真正想学习一些东西的人,最好的方法就是从自己的错误中学习。您展示了其中的几个并重新编写了代码,现在它可以工作了。过去 30 分钟,我正在分析您在这里告诉我的内容,现在一切都说得通了!!我很高兴总有像你这样的人不仅可以帮助而且可以解释!谢谢先生!
  • 鉴于有链表,你真的不需要重读文件;您可以阅读条目,直到遇到错误或 EOF。我还没有解决这个问题。如果你确实解决了这个问题,那么就可以从键盘而不是固定文件中读取。我仍然要做很多更改,但这似乎是使代码合理可靠所必需的和可以做的之间的适当平衡。永远不要对您的代码“完美”感到满意。但是,通常会有一个点达到“足够好”,那就是停止修补的时候了。
猜你喜欢
  • 1970-01-01
  • 2018-06-11
  • 2020-11-20
  • 1970-01-01
  • 1970-01-01
  • 2019-10-15
  • 1970-01-01
  • 1970-01-01
  • 2019-03-03
相关资源
最近更新 更多