2

こんにちは私は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;
}
4

1 に答える 1

2

問題は「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 (i = 0; i < N; i++)、ループで使用しforます — それはより慣用的な C ですfor (i = 1; i <= N; i++)。関数が定義または使用される前に宣言されることを主張するコンパイル フラグを使用するため、関数は静的になります。

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 関数の上に移動しました。

于 2013-05-05T15:11:37.777 に答える