2010-12-02 4 views
1

3 개의 필드가 쉼표로 구분 된 텍스트 파일이 있습니다. 내 텍스트 파일의 내용 예 : 12345, 진정한 프로그래밍 초보자, BS ME 파일을 프로그램에로드하려면 아래 코드를 사용하십시오 .... 내 문제는 때때로 코드가 작동하고 때로는 작동하지 않는다는 것입니다. (오류 메시지가 나타나지 않으면 프로그램이 닫히고 계속되지 않습니다.) 나는 또한 텍스트 파일이 비어 있다는 것을 관찰했다. (아무 것도 쓰여지지 않았다.) 자동으로 닫히고 계속되지 않는다. 귀하의 도움을 높이 평가 될 것입니다. 감사!fgets() 및 strtok()을 사용하여 쉼표 구분 기호로 파일 읽기

int read(){ 
    FILE *stream = NULL; 
    int ctr; 
    char linebuffer[45]; 
    char delims[]=", "; 
    char *number[3]; 
    char *token = NULL; 
    stream = fopen("student.txt", "rt"); 
    if (stream == NULL) stream = fopen("student.txt", "wt"); 
    else { 
      printf("\nReading the student list directory. Wait a moment please..."); 
      while(!feof(stream)){    
       ctr=0; 
       fgets(linebuffer, 46, stream); 
       token = strtok(linebuffer, delims); 
       while(token != NULL){ 
        number[ctr] = linebuffer; 
        token = strtok(NULL, delims); 
        ctr++; 
       } 
      recordCtr++;      
      }      
    recordCtr--; 
    } 
    fclose(stream); 
}  
+0

왜 이렇게 많은 점들을 사용합니까? 그것은 끔찍한 것 같습니다. – unwind

답변

2

발견하면 token을 절대로 복사하지 마십시오. linebuffer을 복사 할 수 없습니다. 그 이유는 다음 행이로드 될 때 그곳의 데이터가 겹쳐 쓰기 때문입니다.

이 줄 :

number[ctr] = linebuffer; 

저장할 token를 참조해야 가장 최근에 토큰을 찾았지만 그렇지 않습니다. 그것은 아마 1 같은 읽어야

strcpy(number[ctr], token); 

을하지만 당신은 공간이 확실하게 선언을 변경해야 할 것 : 분명히

char number[3][32]; 

는,이 경우, 버퍼 오버런 위험을 소개합니다 매우 긴 토큰이 들어 맞지 않습니다. 그것을 어떻게 잘 처리 할 수 ​​있을지 연습으로 남겨 두었습니다. :)

두 개의 숫자를 저장하는 데 사용하고 하나의 문자열 (이름)이 나를 벗어나는 이유는 임시 벡터를 "숫자"라고 부르는 이유입니다.

+0

@unwind 죄송합니다. 나는 이해하지 못한다. 좀 더 설명해 주시겠습니까? Thanks – newbie

+0

그는 "strtok()"에 의해 반환 된 "토큰"을 얻었지만 버리십시오. 대신 필드에 "라인 버퍼"를 지정합니다. – AlastairG

+0

@unwind 좋은 답변이지만, 당신보다 더 많은 버그와 잠재적 인 버그를 발견했다고 생각합니다;) 너무 경쟁력이 있습니까? – AlastairG

1

당신의 fgets() 호출은 크기를 45로 지정해야합니다. 그렇지 않으면 fgets가 NULL 종결자를 쓸 때 버퍼 오버플로가 발생합니다. 그러면 "delims"문자열이 빈 문자열이됩니다.

또한 함수 선언에 int가 반환되는 경우에도 값을 반환하지 않습니다.

"구조용 학생"의 정의가 무엇인지 모르겠지만 strcpy()을 사용할 때 버퍼가 넘칠 수 있습니다. 또한 "recordCtr"을 감소시킵니다. 왜? 쓰기를 위해 파일을 열 수없는 경우 왜 파일을 열어 파일을 엽니 까? 왜? 실패해도 fclose를 NULL 포인터로 호출한다. 그게 많은 도움이 될지 의심 스럽네.

"number"를 초기화하지 않은 것으로 나타났습니다. 첫 번째 행에 세 개의 숫자가 없으면 초기화되지 않은 포인터에서 strcpy()입니다. 아마도 프로그램이 segfault 할 수 있도록 NULL 값을가집니다.

또한 배열의 크기는 3이지만 읽는 행에 3 개 이상의 쉼표로 구분 된 필드가 있으면 배열이 오버플로됩니다.

다른 많은 오류가있을 수 있습니다.

많은 프로그래머가 반환 값 확인, 변수 초기화 등과 같은 좋은 코딩 방법을 수행하는 데 신경 쓰지 않을 수 있습니다. 그들은 종종 이와 같은 코드로 끝납니다. 정말 좋은 프로그래머가되기를 원한다면,이 모든 일을하는 습관을 갖도록 노력하거나 적어도 항상 필요로하는지 아닌지에 대해 생각하십시오.

이 코드에는 잠재적 인 버그가 너무 많습니다. 한 줄의 길이가 45자를 초과하면 어떻게됩니까? 줄 바꿈을 제거하지 마십시오. 문자열을 숫자로 변환하지 않습니다 (number [1]은 문자열 데이터로 보이지만 "numbers"배열에 저장하는 이유는 무엇입니까?) 또는 실제로 fgets에서 데이터를 반환했는지 확인하거나 데이터 수를 확인하십시오. 도망.

+0

나는 5 글자 (ID), 30 글자 (학생 이름), 5 글자 (과정) 만 허용하기 때문에 46 글자를 사용했다. 그런 다음 추가 5 개를 만드십시오. 내 논리가 잘못 되었습니까? 감사합니다 – newbie

+0

내 함수 선언은 int이기 때문에 void로 변경했기 때문에 컴파일러 오류가 발생했습니다 – newbie

+0

아마도'read()'가 시스템 함수이기 때문입니다. 다른 것으로 이름을 변경하십시오. 직장에서 우리는 모든 공용 함수가 자신이 속한 모듈/구성 요소의 이름으로 시작해야한다는 코딩 표준을 가지고 있습니다. 예 : 당신은 그것을 StudentDB_Read()라고 부를 수 있습니다. – AlastairG

1

구매자가주의하도록하십시오.

strtok에는 몇 가지 문제가있을 수 있습니다.

"1, 2, 3"은 3 개의 토큰을 생성합니다.

"one, three"은 2 개의 토큰을 산출합니다.

+0

무엇을 의미합니까? – newbie

+0

그것은 그것이 무엇을 의미 하는지를 의미합니다. "토큰"이 무엇인지 이해합니까? 그렇지 않다면, 당신은'strtok'을 사용해서는 안됩니다; 'strtok'의 'tok'가 짧다고 생각하니? –