構造体のscanf char * wordは最後の入力のみを表示します

私は以下のヘッダーを使用することのみ許可されています

#include 
#include  

struct student を次のように定義しました:

struct dict
{
    char* word;
    struct dict* link;
};

多くの機能がありますが、今のところ問題がある機能は1つだけです。 この関数は、リンクの最後に特定の名前のstruct dictを挿入します。

struct student *Linsert(struct dict *list, char *name)
{
    struct student *pnew;
    struct student *pn;
    int exist = 1;

    pnew = (struct dict *)malloc(sizeof(struct dict));
    pnew -> next = NULL;
    pnew -> name = name;

    if (list != NULL)
    {
        for (pn = list; pn -> next != NULL; pn = pn -> next) ;
        pn -> next = pnew;
    }
    else
        list = pnew;

    return list;
}

次の関数を使用して、

  //リスト内のすべての値を出力する
void printList(構造体dict *リスト);
 

これは私がしました:

int main(void)
{

    struct dict *list = NULL;

    char *name;

    while (1) {
        scanf("%s", name);
        if (name == 'Q')
            break;

        list = Linsert(list, name);
        printList(list);
    }
    return 0;
}

入力のために、私は3つをタイプしました apple banana orange

ここの問題は何ですか?

0
これは宿題のように見える。また、デバッガ(gdbなど)を入手してコードを実行するのに適しています。
追加された 著者 Zach Johnson,
常にすべての警告でコンパイルし、それらを無視しないでください。
追加された 著者 Kerrek SB,
この実際のコードですか?あなたの構造体は struct dict * link を持っていますが、コードは - > next を使用します。これはコンパイルしてはいけません。 コードをコピーして貼り付け、再入力しないでくださいしてください。
追加された 著者 sarnold,
質問の書式設定方法、特に次回のコードブロックの書式設定方法を見てください。
追加された 著者 Andrew Marshall,
@KerrekSB -Wall -Wextra -Werror は、常にコード
追加された 著者 Andrew Marshall,

5 答え

あなたのコードには2つの問題があります。

  • scanf の文字列を格納するのに十分な大きさの配列を char 配列に渡す必要があります。
  • Linsert に渡された文字列をコピーする必要があります( strdup を使用してください)。
3
追加された

あなたの main スニペットだけでは、たくさんの問題があります。

  • name は初期化されていないポインタです。それはあなたが割り当てていないし、使用することが許可されているメモリ内のいくつかの未知の場所を指しているため、未定義の動作が発生します。スタック上に20個の char の配列を割り当て、 scanf にこのバッファに入力を保存させるには char name [20]

  • char (文字列の先頭を指すポインタ)と char 'Q' を比較しています> - コンパイラの警告があなたに伝えるように、ポインタと整数値を比較しています。文字列の内容を 'Q' の値と比較していない場合、 name のメモリアドレスと 'Qの整数値を比較しています' name という文字列と "Q" という文字列を比較する場合は、 strcmp を使用して戻り値0を確認します。 >

また、あなたが気づいたように、 Linsert に渡された変数のコピーを作成したいときは、毎回メモリ内の同じ場所にポインタを渡し、これに変更を加えますメモリのブロックはあなたのアイテムのそれぞれを変更します。

あなたがコンパイラの警告を上げると、より多くの警告が得られます。

2
追加された

1つの問題は、 word メンバーがポイントするためのストレージを割り当てていないことです。 name にポイントするためのスペースも割り当てられていません。それがトラブルの原因です。

name のスペースを割り当てる必要があります。最も簡単な方法は次のとおりです。

char name[128];

単語を格納するスペースを確保する必要があります。また、 name の内容を word にコピーして、次の行が name 、保存された word は破壊されません。

コードを修正するには、次のようにします:

struct student *Linsert(struct dict *list, char *name)
{
    struct student *pnew;
    struct student *pn;

    pnew = (struct dict *)malloc(sizeof(struct dict));
    if (pnew == 0)
        ...error...
    pnew->next = NULL;
    pnew->word = malloc(strlen(name) + 1);
    if (pnew->word == 0)
        ...error...
    strcpy(pnew->word, name);

    if (list != NULL)
    {
        for (pn = list; pn->next != NULL; pn = pn->next)
            ;
        pn->next = pnew;
    }
    else
        list = pnew;

    return list;
}

メモリ割り当てのエラーチェックを省略しないでください。苦労します。あなたが忘れたときにあなたを噛むでしょう。

Stylistically, do not use spaces around either -> or .; they are operators that bind very tightly, and they should not be spaced out like other binary operators.

便利な関数 strdup()があります。これは文字列を複製しますが、標準のC言語ではありません(標準のPOSIXです)。

1
追加された

名前のためにメモリを割り当てていないので、scanfはランダムな場所に書き込んでいて、毎回ループを介して上書きします。

1
追加された

name はcharポインターなので、各 dict 構造体のフィールドへの割り当ては、それが指す最新の値を使用します。

0
追加された