3

ユーザーが完了を押すまで、ユーザー入力を受け取る簡単なプログラムを作成しようとしています。そして、彼らがそうすると、プログラムは彼らがタイプしたものすべてを出力します。私はそれのほとんどが機能していると感じており、プログラムは正常にコンパイルされますが、入力を入力して完了を押すと、入力を入力した行と同じ数の行が出力されます。私はそれを引き出しました。このコードはうまくいくはずです。また、私はCに非常に慣れていないので、誰かが何が悪いのかを教えてくれたり、提案をくれたりすることができれば.

#include <stdio.h>
#include <stdlib.h>

struct llist {          
struct llist* nxt; 
char* string;
};              

void add(struct llist **tail, char* str) { 
    struct llist* n_ptr = (struct llist*)malloc(sizeof(struct llist));
    (**tail).string = str; 
    (**tail).nxt = n_ptr;   
        (*tail) = n_ptr; 
    n_ptr->nxt = (struct llist*)0;
};

void print(struct llist *Head) {
    struct llist* ptr;
    ptr = Head;
    while(ptr->nxt){ 
        printf("%s\n", ptr->string);
        fflush(stdout);
        (ptr = (ptr->nxt)); }
}

int main() {
    char* line = NULL;
    size_t size = 100; 
    char* done = "done";

    struct llist head; 
    struct llist* tail = (struct llist*)malloc(sizeof(struct llist));

    tail = &head; 

    do { 
    getline(&line, &size, stdin); 
    add( &tail , line ) ;   
    } while ( strncmp(line, done, 4) != 0 );

    print(&head);

    return 0;
}
4

4 に答える 4

3

リストには、データ自体ではなく、データへのポインターのみが含まれています。したがって、リストに追加されたデータが変更されると、リストのデータも変更されます。への呼び出しごとにaddstrは同じです。つまり、同じポインターをリストに何度も追加しただけです。

手早く醜い修正を行うには、次のように変更します。

(**tail).string = str;

に:

(**tail).string = strdup(str);
于 2012-06-27T01:24:42.297 に答える
1

あなたのためのいくつかのメモ。

  • getline()バッファへのポインタを取ります。テキストは、ポインターが示す場所に保存されます。あなたのテキストはどこに行きますか?次のいずれかを行う必要があります。

line = malloc(size);

多分

char line[100];

これらのいずれかが問題を解決します。ただしgetline()、バッファが十分に大きくない場合はバッファを動的に拡張するため、おそらくmalloc()解決策が望ましいでしょう。(バッファを動的に拡張するときにgetline()呼び出そうとするかどうかはわかりません。もしそうなら、それが非常に望ましいです。)free()malloc()

編集: 上記の点は無視してかまいません! getline()null ポインターで開始すると、バッファが割り当てられるほど十分にスマートであることがわかります。したがって、コードは書かれているとおりに正しいです。申し訳ありません。に詳しくありませんgetline()

  • リンクされたリストのコードは、ほとんどの場合malloc()、新しいノードを作成するために呼び出します。しかし、何らかの理由で、単一のノードをhead静的に宣言します。このような小さなプログラムでは問題ありませんが、大きなプログラムを作成すると混乱するでしょう。リンクされたリストを解放するときは、最初のノードを解放しないように注意する必要があります (これは を使用して割り当てられていないためmalloc()です)。個人的には、両方を作成headtailてポインターにし、両方をに設定して開始しますNULL(長さゼロのリンクリストの場合)。これを行う最も簡単な方法は、add()関数にポインターの引数を取り、headセットアップさせることです。headリンクされたリストに最初の構造体を追加するとき。tailまた、最初の構造体をリンクされたリストに追加するときはまだ設定されていないため、少し注意する必要があります。そのため、新しいノードを前のノードにリンクしようとしてはいけません。 . したがって、 への最初の呼び出しは、構造体の新しいインスタンスをadd()設定headしてポイントする必要があり、新しいインスタンスのポインターは null に設定されている必要があります。他の呼び出しは、新しい構造体を既存のリンクされたリストにリンクする必要があります。tailnextadd()

  • 実際のプログラムでは、常に関数の戻り値をチェックします。malloc()失敗する可能性があります。常に機能すると仮定しないでください。しかし、クラスに対してこれを行っていて、それらのエラーチェックを行う必要がない場合は、スキップできると思います。ただし、注意深い習慣を早期に習得することは決して悪いことではありません。

  • @David Schwartzの回答に記載されているようにstrdup()、各文字列のコピーを取得するには電話する必要があります。

于 2012-06-27T01:33:46.783 に答える
1
struct llist head; 
struct llist* tail = (struct llist*)malloc(sizeof(struct llist));

tail = &head;

また、ここでの malloc は不要であることも指摘しておきます。とにかく、メモリリークを引き起こしている3行目の割り当てでそれを破棄しています。

于 2012-06-27T01:38:22.673 に答える
0
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef enum {FAILURE, SUCCESS} ReturnType;

typedef struct node_t Node;
struct node_t {
    Node* next;
    char* data;
};

Node* nodeCreate(char* str) {
    Node* res = (Node*) malloc(sizeof(Node));
    if (res == NULL) {
        return NULL;
    }

    res->data = (char*) malloc(strlen(str) + 1);
    if (res->data == NULL) {
        free(res);
        return NULL;
    }

    strcpy(res->data, str);
    res->next = NULL;

    return res;
}    

void nodeDestroy(Node* node) {
    free(node->data);
    free(node);
}    

typedef struct list_t {
    Node* head;
    Node* tail;
} List;

List* listCreate() {
    List* res = (List*) malloc(sizeof(List));
    if (res == NULL) {
        return NULL;
    }

    res->head = (Node*) malloc(sizeof(Node));
    if (res->head == NULL) {
        free(res);
        return NULL;
    }
    res->head->next = NULL;
    res->head->data = NULL;
    res->tail = res->head;

    return res;
}

void listDestroy(List* list) {
    if (list == NULL) {
        return;
    }

    Node* curr = list->head;
    Node* next = NULL;

    while (curr != NULL) {
        next = curr->next;
        nodeDestroy(curr);
        curr = next;
    }
    free(list);
}

ReturnType listAdd(List* list, char* str) {
    if (list == NULL) {
        return FAILURE;
    }

    Node* newNode = nodeCreate(str);
    if (newNode == NULL) {
        return FAILURE;
    }

    list->tail->next = newNode;
    list->tail = list->tail->next;

    return SUCCESS;
};

void listPrint(List* list) {
    if (list == NULL) {
        return;
    }

    Node* curr = list->head->next;
    while(curr != NULL){
        printf("%s\n", curr->data);
        curr = curr->next;
    }
}

#define MAX_LINE_SIZE 100

int main() {
    setvbuf(stdout, NULL, _IONBF, 0);
    char line[MAX_LINE_SIZE];
    char* done = "done";

    List* list = listCreate();
    if (list == NULL) {
        fprintf(stderr, "Failure!\n");
        return 0;
    }

    do {
        scanf("%s", line);
        if (listAdd(list , line) == FAILURE) {
            fprintf(stderr, "Failure!\n");
            listDestroy(list);
            return 0;
        }
    } while (strncmp(line, done, 4) != 0);

    listPrint(list);

    listDestroy(list);

    return 0;
}
于 2012-06-27T02:40:36.943 に答える