C언어 구조체&포인터관련 질문입니다.

-@Naver의 이미지

db* tmp;
 
db* target;
 
void load() {
 
 FILE* fp;
 
 fp = fopen("C:", "r");
 
 char* name = malloc(sizeof(char) * 21);
 
 char* num = malloc(sizeof(char) * 16);
 
 char* bday = malloc(sizeof(char) * 9);
 
 root = malloc(sizeof(db));
 
 root->nameptr = NULL;
 
 root->numptr = NULL;
 
 root->bdayptr = NULL;
 
 root->next = NULL;
 
 int cnt = 0;
 
 while (fscanf(fp, "%s %s %sn", name, num, bday) != -1) { //문제의 while 문
 
  if (root->next == NULL) {
 
   target = init(root);
 
   root->next = target;
 
  }
 
  else {
 
   target = init(tmp);
 
   tmp->next = target;
 
  }
 
  target->nameptr = name;
 
  target->numptr = num;
 
  target->bdayptr = bday;
 
  tmp = target;
 
 }
 
}
 
db* init(db* curdb) {
 
 db* info = (db*)malloc(sizeof(db));
 
 info->nameptr = malloc(sizeof(char) * 21); ;
 
 info->numptr = malloc(sizeof(char) * 16); ;
 
 info->bdayptr = malloc(sizeof(char) * 9); ;
 
 info->next = curdb->next;
 
 return info;
 
}
 
typedef struct infst {
 
 char* nameptr;
 
 char* numptr;
 
 char* bdayptr;
 
 struct infst* next;
 
} db;

txt 파일에서 한줄씩 불러와서 연락처를 링크드리스트 형태로 주욱 연결하는식인데

문제의 while문에서 첫줄은 잘불러와서 노드에 잘저장하는데, while 2회차루프에서 첫번째 노드내용물이 2번째로 가야할 내용물로 싹바뀌어버립니다.

물론 두번째 노드에는 2번째 내용물이 잘들어가고요.

3회차 루프에는 첫번째 두번째 세번째 노드 전부에 3번째 내용물이 들어갑니다.

디버그를 통해서 한줄씩 넘겨본결과 while문 2회차 조건문 참조를 하자마자 첫번째 노드의 내용물이 조건문에서 받아오는 정보들로 바뀌어버립니다.

어디서 무엇이 잘못되어버린걸까요?

익명 사용자의 이미지

그렇게 짰기 때문이지요.

 char* name = malloc(sizeof(char) * 21); 
 char* num = malloc(sizeof(char) * 16);
 char* bday = malloc(sizeof(char) * 9);

name, num, bday 포인터에 메모리를 할당하는 이 코드가 함수 전체에 걸쳐 단 한 번만 실행된다는 사실을 주목하세요. 이들 포인터는 함수가 반환되는 순간까지 동일한 메모리를 가리키고 있습니다.

이후 fscanf문은 name, num, bday가 가리키는 메모리 영역에 문자열을 입력받습니다.

그러고 나서...

  target->nameptr = name; 
  target->numptr = num; 
  target->bdayptr = bday;

아래 내용을 정확하게 이해하려면 초보자에겐 시간이 좀 필요할 수 있습니다. 하지만 꼭 필요한 일입니다.

(1) 여기서는 문자열이 복사되고 있지 않습니다. 복사되고 있는 건 문자열을 가리키는 포인터입니다.
(2) target->nameptr은 name의 사본으로서 동일한 메모리 영역을 가리키게 됩니다.
(3) 이후에 fscanf가 다시 호출되어 name이 가리키는 영역에 새 문자열을 쓴다면, target->nameptr도 같은 곳을 가리키고 있었으므로, target->nameptr이 가리키는 문자열도 자연스럽게 같이 바뀝니다.

C언어에서 문자열을 다룰 때는, 내가 직접적으로 다루고 있는 것이 문자열 그 자체가 아닌 문자열에 대한 포인터라는 사실을 계속해서 상기할 필요가 있습니다.

문자열을 제대로 복사하기 위해서는,
(1) 사본이 될 문자열을 만들기 위한 메모리를 할당하고 (e.g., malloc 등을 이용)
(2) 그 자리에 실제로 문자열의 사본을 만들어 넣어야 합니다. (e.g., strncpy 등을 이용)

-@Naver의 이미지

친절하신 답변 감사합니다. 문자열에 관한 조언 항상 명심하도록하겠습니다.

name, num, bday의 선언을 while문 안으로 가져와서, 새로선언한후 fscanf로 입력받도록 했습니다. 덕분에 궁금증과 문제도 해결하고, 새로이 배워갑니다. 감사합니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.