2017-12-18 1 views
0

각 노드가 문자열을 저장하는 링크 된 목록을 만들려고합니다. 그러나 각 노드가 모든 동일한 문자열을 저장하는 데 문제가 있습니다. 단일 노드. main()의 끝에서 각 노드에 저장된 단어를 출력하고 항상 전체 목록에 입력 된 마지막 문자열을 반복합니다.링크 된 문자열 목록에는 각 노드에 대해 동일한 문자열이 있습니다.

나는 문자를 문자열로 만들면 각 문자가 올바른 노드에 저장되는 것이므로 완벽하게 작동하기 때문에 어떤 일이 발생하는지 전혀 알지 못합니다.

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

struct wordnode { 
    char *word; 
    struct wordnode *next; 
}; 

struct wordnode *link = NULL; 

void addword(char *aword); 

int main(void) { 


    char *aword; 
    int i; 

    for(i = 0; i < 10; i++) { 
     scanf(" %s", aword); 
     addword(aword); 
    } 
    printf("\n"); 
    for(; link != NULL; link = link->next) { 
     printf("|%s ", link->word); 
    } 

    printf("|\n"); 
    return 0; 
} 

void addword(char *aword) { 
    struct wordnode *cur, *prev, *new_node; 

    new_node = malloc(sizeof(struct wordnode)); 

    new_node->word = aword; 

    for(cur = link, prev = NULL; cur != NULL; prev = cur, cur = cur->next) { 
     ; 
    } 

    new_node->next = cur; 

    if(prev == NULL) { 
     link = new_node; 
    } else { 
     prev->next = new_node; 
    } 
} 
+3

여러 가지 문제가 있습니다. 그것은 초기화되지 않은 포인터를 전달하는'scanf '를 사용하는 방법으로 시작됩니다. 'scanf' 함수는 입력을 기록하기에 충분한 할당 메모리를 필요로합니다. 메모리 자체를 할당하지는 않습니다. –

+2

입력 한 문자열을 복사해야합니다. –

+2

포인터가 마술처럼 메모리를 생성하지 않습니다. 'char * aword'는 초기화되지 않았으며 정의되지 않은 위치를 가리 킵니다. 이와 같이 사용하면 정의되지 않은 동작이 호출됩니다. char 배열을 할당하려면 * char aword [SIZE];를 사용해야한다. 그리고 단순히 포인터 ('new_node-> word = aword;')를 복사해서는 안되며 지시 한 위치를 중복시켜야한다 ('strdup' 참고). 궁극적으로 C에서 할당 된 모든 메모리를 일관되게 * 비우는 것이 좋습니다. C :-) 연습에 행운을 빕니다 ... –

답변

0

char * aword은 초기화되지 않고 위치합니다. 그것은해야한다 :

char aword[100]; 

(100 단지 숫자, 배열의 크기 당신은 당신이 원하는 숫자로 교체 할 수 있습니다.) 코드에 많은 문제가 있습니다

+0

주석에서 언급했듯이 이것은 유일한 것이 아니다. 문제가 있으시면 답을 좀더 잘 풀어주세요. –

+0

이 답변은 짧고 간단하기 때문에 나에게 매우 유용합니다. 그것은 다른 문제를 알아 내게했습니다. scanf가 자동으로 문자열에 메모리를 할당했다고 생각했기 때문에 그 이유는 내가 초기화하지 않았기 때문입니다. –

1

. 그들 중 일부는 이미 언급되었습니다. 코드는 다음과 같습니다. 코드 끝 부분에 설명이 나와 있습니다.

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

#define STR2(x) #x 
#define STR(X) STR2(X) 
#define MAXWORD 10 
#define MAXWORDLEN 20 

struct wordnode { 
    char *word; 
    struct wordnode *next; 
}; 


struct wordnode* addword(char *aword, struct wordnode *link); 
void printList(struct wordnode*link); 
void freeList(struct wordnode *link); 

int main(void) { 
    char aword[MAXWORDLEN+1]; 

    struct wordnode *link = NULL; 
    for(size_t i = 0; i < MAXWORD; i++) { 
     if(scanf("%" STR(MAXWORDLEN) "s", aword[i]) == 1){ 
      link = addword(aword, link); 
     } 
     else{ 
      fprintf(stderr, "%s\n","Error in input"); 
      exit(1); 
     } 
    } 

    printList(link); 

    freeList(link); 
    return 0; 
} 
void printList(struct wordnode*link){ 
    while(link){ 
     printf("%s \n", link->word); 
     link = link->next; 
    } 
} 
void freeList(struct wordnode *link){ 
    struct wordnode *temp; 
    while(link){ 
     temp = link; 
     link = link->next; 
     free(temp); 
    } 
} 

struct wordnode* addword(char *aword, struct wordnode *link) { 

    struct wordnode *new_node = malloc(sizeof(struct wordnode)); 

    if(new_node == NULL){ 
     fprintf(stderr, "%s\n", "Error in malloc"); 
     exit(1); 
    } 
    new_node->word = strdup(aword); 
    if(new_node->word == NULL){ 
     fprintf(stderr, "%s\n", "Error in strdup"); 
     exit(1); 
    } 
    new_node->next = NULL; 

    if(link == NULL){ 
     return new_node; 
    } 
    struct wordnode *cur = link; 
    while(cur->next != NULL){ 
     cur = cur -> next; 
    } 
    cur->next = new_node; 
    return link; 
} 

일부 문자열 (nul 종료 문자 배열)을 저장하고 목록에 추가하려고합니다. 또한 예제 구현에서 꼬리 부분에 목록에 추가하려고했습니다.

정리해 -

  • scanf는 입력 된 데이터를 저장할 수있는 메모리에 대한 포인터를 요구한다. 그러나 당신은 초기화되지 않았습니다.

  • 두 번째로 문자열을 복사하는 방식은 얕은 복사본 (이미 기존 메모리를 가리키고 있음)이었습니다. strdup 또는 malloc - memcpy 또는 malloc-strcpy을 사용하여 복사해야합니다.

  • POSIX strdup()을 사용할 수없는 경우 Jonathan Leffler가 언급 한 것을 사용할 수 있습니다.

  • 여기서 우리는 freeList() 기능을 사용하여 할당 된 메모리를 해제했음을 알 수 있습니다. 할당 된 메모리로 작업을 마쳤 으면 메모리를 비우십시오.

  • malloc의 반환 값을 캐스트하지 마십시오.

  • 또한 malloc이 반환 값을 확인하는 데 성공했는지 확인하십시오.

  • 목록 머리글을 전역 변수로 사용했습니다. 여기에는 필요하지 않습니다.

+0

감사하지만 strdup을 사용할 수는 없지만 ISO C로 작업하고 있습니다. 하지만 구조체에 특정 크기의 배열에 문자가 있으므로 포인터 대신 초기화되고 scanf를 호출하여 문자열을 저장합니다 malloc을 호출 한 후 각 노드의 배열에 직접적으로 접근 할 수있다. malloc은 aword 변수를 완전히 제거하는 것으로 잘 동작한다. –

0

문자열에 메모리를 할당하지 않았습니다. 결과적으로 aword은 가비지 값을 포함하고 scanf으로 전달하면 정의되지 않은 동작입니다. aword의 주소가 0x7fffe4e0cdf0이고 scanf의 주소가 0x7fffe4e0cdf0 인 문자열을 저장하고이 주소를 addword 함수에 전달하고 구조체 멤버 word도 동일한 값으로 업데이트됩니다. 다음 scanf는 aword이 가리키는 동일한 메모리에 새 값을 저장하고 함수로 전달합니다.결과적으로 연결된 모든 목록의 word은 동일한 메모리 위치를 가리 킵니다. 이상적인 해결책은 스캔중인 각 문자열에 메모리를 할당하고이를 'addword'함수에 전달하는 것입니다.

관련 문제