strtok로 토큰 쪼개서 배열에 저장하는데 오류가 생깁니다.

Hubert Lee@Google의 이미지

소스에 궁금한 부분을 주석 달아보겠습니다 ㅠㅠ
도대체 어떤 논리적 오류인지 감이 전혀 안잡힙니다.

#include <stdio.h>
#include <string.h>
 
int main(){
    FILE *fp = fopen("optab.txt","r");
    char buf[100], * ptr, * store[100];
    int cnt=0;
 
    while (feof(fp)==0){
        fgets(buf,sizeof(buf),fp);
        ptr = strtok(buf,",");
 
        while(ptr!=NULL){ //
            printf("%s\n",ptr);
            //store[cnt]=ptr; // 1)번 의문. 제 생각에는 이 방법이나 strcpy처럼 하면 배열에 저장이 되어야 할 것 같은데 저장이 안됩니다. 이상한 값이 반복해서 들어갑니다.
            //2)번 의문. 심지어 strcpy는 segmentation fault가 뜹니다. 어째서..? ptr은 NULL이 못올텐데... ptr값을 print해보면 NULL로 나옵니다.
            strcpy(store[cnt], ptr);  // 3)번 의문. 가장 큰 의문은 while 문 내에서 ptr 값을 출력하면 정상적으로 토큰이 분리되어 출력됩니다.
            ptr=strtok(NULL,"\n");  //store[cnt]=ptr을 하고 while문 내에서 store배열 출력해도 정상적으로 출력이 되어요. 그런데!!!!
 
            cnt++;
        }
    }
    fclose(fp);
 
    for(int j=0;j<10;j++){
        printf("store:%s",store[j]); // 이렇게 while문 바깥에서 출력하면 토큰이 정상분리가 안되고  optab.txt의 맨 끝 값만 출력됩니다. 반복해서요. 도대체 왜!!!????? ㅠㅠ.
    }
 
    return 0;
}

optab.txt

ADD,18
AND,58
COMP,28
LDA,00
STA,0C

라스코니의 이미지

store는 포인터 배열이지 char 배열이 아닙니다. 공간을 할당받지 않은 char 포인터 배열에 strcpy를 하면 안되죠.

Hubert Lee@Google의 이미지

그렇군요. 감사합니다.

동적 배열을 써서 해결했습니다!

김정균의 이미지

buf_t[100] 을 만들어서 buf 의 내용을 buf_t 에 복사한 다음 buf_t 를 가지고 strtok 를 해 보세요.

그리고 while loop 도 feof 말고 fgets 로 직접 control 하세요

while ( fgets (buf, sizeof (buf), fp) != NULL ) {
    strcpy (buf_t, buf);
    ptr = strtok (buf_t, ",");
    ...
}

다음 코드는 char **store 가 100 개 있다는 의미죠. 즉, 메모리 할당이 되어 있지 않은 **store 에 strcpy 를 해서 segfault 가 발생 하는 겁니다.

char *store[100];

의도하신 바는

char store[10][100];

로 선언해야 하지 않았을까 싶네요

마지막으로 strtok 는 thread safe 에 취약 하므로 strtok_r 또는 strsep 를 사용하라고 권장하고 있습니다.

Hubert Lee@Google의 이미지

답변 감사드립니다!
늦게 답을 달아 죄송합니다. 여러 번 곱씹어 보느라 늦었습니다.
그런데 feof말고 fgets를 써야 하는 이유가 있는지요?
선언만 하고 할당을 안한 문제는 동적배열로 해결했습니다. 감사합니다!

김정균의 이미지

fgets/feof 에 대해서는 https://kldp.org/node/3651 참고해 보세요.
그 외에도 google 에서 두 함수로 검색 하시면 해당 현상에 대한 글들을 쉽게 찾을 수 있습니다.

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.