2017-11-12 4 views
-4

코드를 실행하면 세그먼트 화 오류가 발생합니다. 난 그냥 파일을 열고 그것의 데이터 행을 읽으려고합니다. 나는 내가 이해하지 못하는 것이 있다는 것을 확신한다. 어떤 도움을 주시면 감사하겠습니다.세그먼트 화 오류가 계속 발생합니다.

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

    void get_num_lines(const char *fname, int *rows); 

    int main (int argc, char* argv[]) { 
     int rows = 0; 
     char *ptr1 = NULL; 
     char str1 = '.csv';     
     ptr1 = strchr(argv[1], str1); 
     if(ptr1 != NULL){ 
      const char *fname = argv[1]; 
      get_num_lines(fname, &rows); 
     } 

     return(0); 
    } 

    void get_num_lines(const char *fname, int *rows) 
    { 
     FILE *fin; 
     fin = fopen(fname, "r"); 
     printf("the input file name is %s", fname); 

     char line[256] = {0x0}; 
     while(!feof(fin)){ 
      fgets(line, 255, fin); 
      if(line != NULL){ 
      rows++; 
    } 
} 




    } 


    fclose(fin); 

}

+0

실패에 .csv는 명령 줄을 통해 입력됩니다. – jruo

+0

'fopen'이 파일을 열 수없고 널 포인터를 반환하면 어떨까요? 그리고 Eric Lippert의 [작은 프로그램을 디버깅하는 방법] (https://ericlippert.com/2014/03/05/how-to-debug-small-programs/)을 읽고 시간을내어 디버거가 이와 같은 충돌을 잡을 수 있습니다. –

+2

또한 [fgets'] (http://en.cppreference.com/w/c/io/fgets) *가 반환하는 것을 확인해야합니다. 배열'line'은 첫 번째 원소에 대한 포인터로 감쇠 될 것이고 결코 null 포인터가되지 않을 것입니다. 마지막으로 [while (! feof (file))]이 항상 잘못된 이유는 무엇입니까?] (https://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong) –

답변

3

코드에는 몇 가지 중요한 중요한 문제가 있습니다. 주된 하나는 파일을 검증하지 못했기 때문에 실제로 파일을 읽는 중입니다.. fopen의 유효성을 검사하지 않으면 정의되지 않은 동작을 호출 할 때 잘못된 fin 포인터에서 읽으려고하는 다음 호출에서 알 수 없습니다.

Why is “while (!feof (file))” always wrong?을 설명하는 링크를 가리키고 있습니다. fgets의 반환을 확인하는 것만이 필요한 것입니다.

다음으로 함수에 대한 매개 변수로 rows에 대한 포인터를 전달하는 것이 좋지만 올바르게 업데이트하지는 않습니다.

rows++;  /* this is wrong. this increments the address! (not the value) */ 

당신이 포인터를 통과하기 때문에, 당신은 그 주소에 저장된 값을 증가해야한다가 아니라 주소 자체, 예를 들면 : get_num_lines에서 당신과 갱신을 시도

(*rows)++; /* note the use of (..) for correct C-operator precedence */ 

"실제로 포인터를 전달하는 이유는 무엇입니까?" 왜 단지 get_num_lines의 뜻 깊은 반환을 이용하고 발신자에게 회선의 수를 단순히 반환합니까? size_t get_num_lines (FILE *fin)

참고 : 일반적인 관행 열고 파일이 호출하는 함수 (여기 main())에서 읽을 열려 있는지 확인하고 매개 변수가 아닌 파일 이름으로 FILE * 포인터를 전달하는 것입니다. 파일 이름을 전달하고 함수에서이 파일을 모두 처리하는 것은 잘못이 아닙니다. 일반적인 접근 방식이 아닙니다.

그러나 파일의 행 수를 계산하기 위해 단순히 fgets을 호출 할 수는 없습니다. 줄 수를 늘리기 전에 버퍼에 줄이 맞는지 확인해야합니다 (예 : 전체 줄을 읽은 다음 더 긴 줄의 첫 번째 254 문자가 아님). 이를 수행하려면 fgets으로 읽은 행의 길이를 확인하고 마지막으로 읽은 문자가 '\n'인지 확인해야합니다.

파일이 파일의 비 POSIX의 끝 (이 최종 '\n' 누락 의미)가있는 경우, 라인 카운트가 1에 의해 너무 적은 원인이 될 것입니다 한 번 더 (불행하게도 공통) 문제가 있습니다. 이것은 최종 문자를 올바르게 검증하는 부작용이며 카운트 기능을 제대로 작동시키기 위해서는 '\n'이 필요합니다. 파일에 최종 '\n'이 없으면 마지막 행이 계산되지 않게됩니다. 고맙게도 이는 단순히 행의 끝이 읽히지 않았 음을 나타내는 플래그를 설정 한 다음 fgets 읽기 루프를 종료 한 후 플래그가 설정되어 있는지 확인하는 방식으로 처리됩니다.

size_t fgets_nlines (FILE *fp) 
{ 
    int noeof = 0; 
    size_t n = 0; 
    char buf[BUF_SIZE] = ""; 

    while (fgets (buf, BUF_SIZE, fp)) {  /* read until EOF */ 
     size_t len = strlen (buf);   /* get buf length */ 
     if (len && buf[len-1] != '\n') { /* if not complete line */ 
      noeof = 1;      /* set flag no EOL found */ 
      continue;  /* read until all chars in line are read */ 
     } 
     noeof = 0; 
     n++; 
    } 
    if (noeof)   /* handle non-POSIX EOF (add 1 to count) */ 
     n++; 

    return n; 
} 

POSIX 의해 제공 함수 배향 제 라인을 필요로하지 않는다 :

함수 오픈 FILE* 포인터를 가지고 읽기 및 본 될 수 행의 수를 반환 모두 그 조각을 씌우고 파일 검사의 끝은 POSIX getline입니다. 또한 라인의 길이에 관계없이 충분한 스토리지를 할당 할 수있는 이점이 있습니다. (또한 단점으로 간주 될 수도 있음).

size_t getline_nlines (FILE *fp) 
{ 
    size_t lines = 0, n = 0; 
    char *buf = NULL; 

    while (getline (&buf, &n, fp) != -1) 
     lines++; 

    free (buf); 

    return lines; 
} 

중 다음과 같이 쓸 수있다 (당신은 함수 이름을 조정해야)를 사용하여 간단한 예제 프로그램을 : 당신은 비슷한으로 getline과 같은 일을 할 수 있습니다. 프로그램의 첫 번째 인수로 읽을 파일 이름이 필요합니다 (또는 인수가없는 경우 기본적으로 stdin에서 읽음). Linux에서 wc -l과 비슷한 출력을 제공하고 행 번호 출력의 일부로 읽은 파일 이름을 추가합니다. name이 인수로 제공되었거나, 단지 stdin에서 읽으면 라인 수만 출력합니다.

#include <stdio.h> 
#include <stdlib.h>  /* for free if using getline */ 
#include <string.h> 

#ifndef BUF_SIZE  /* fgets buffer size */ 
#define BUF_SIZE 8192 
#endif 

size_t fgets_nlines (FILE *fp);  /* comment/uncomment as required */ 
// size_t getline_nlines (FILE *fp); 

int main (int argc, char **argv) { 

    size_t nlines = 0; 
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin; 

    if (!fp) { /* validate file open for reading */ 
     perror ("file open failed."); 
     return 1; 
    } 

    nlines = fgets_nlines (fp); 
    // nlines = getline_nlines (fp); /* same note, comment/uncomment */ 
    if (nlines) { 
     if (argc > 1) 
      printf ("%zu %s\n", nlines, argv[1]); 
     else 
      printf ("%zu\n", nlines); 
    } 

    if (fp != stdin) fclose (fp); /* close file if not stdin */ 

    return 0; 
} 

봐 일들을 통해, 관련 문제 및 fgetsgetline가 아닌 POSIX EOF 이유를 처리하는 방법의 차이에 대해 생각합니다. 추가 질문이 있으면 알려주십시오.

1
char str1 = '.csv';    

단일 인용 연구를 characte하지만 여러 할당하는이 있어야합니다. 마지막 문자 만 지정합니다. 그래서 그것은 char str1 = 'v'처럼 취급 할 것입니다; 그것의 목적을 제공하는 경우 다음 문제는, 그렇지 않으면

char *str1 = ".csv"; 

대신 NULL라인을 비교하는 등 beelow 수정하지 NULL로는 fgets()의 반환 값을 비교합니다. 왜냐하면 fin이 EOF에 도달했을 때 fgets()는 NULL을 반환하기 때문입니다.

ret = fgets(line, 255, fin); 
     if(ret != NULL){ 
     rows++; 
0

몇 가지 : 2. fopen에 종료 1. 검사는 argc 당신이 목록에서 프로그램 EXE 옆에 1 인자가 있는지 확인 (> 1는 argc) 내가 읽은하려고 파일이 있습니다