2012-04-09 6 views
0

내 프로그램에서 세그 폴트가 발생했으며 그 원인이나 원인을 찾는 방법이 확실하지 않습니다. 어떤 도움이라도 대단히 감사하겠습니다!C에서 세그 폴트의 원인

코드에서 한 단어 씩 읽으려고 시도하지만 줄 번호를 추적해야합니다. 그런 다음 데이터가 단어와 줄 번호 인 연결된 목록을 만들려고합니다.

(두 개의 파일이 함께이 컴파일)

void main(int argc, char **argv){ 
    file = fopen(argv[1],"r"); 
    struct fileIndex *fIndex = NULL; 
    delimiters = " .,;:!-";/*strtok chars to seperate*/ 
    int wCount = wordcount(file);/*number of words in file*/ 
    char **str[wCount+1];/*where the lines are being stored*/ 
    int j=0; 
    while(!feof(file)){/*inserting lines*/ 
     fscanf(file, "%s", &str[j]); 
     j++; 
    } 

    char *token, *cp; 
    int i; 
    int len; 
    for(i = 0; str[i]; i++){/*checking to insert words*/ 
     len = strlen(*str[i]); 
     cp = xerox(*str[i]); 
     token = strtok(cp, delimiters); 
     if(!present(fIndex, token)){ 
      insert(fIndex, i+1,token); 
     } 

     while(token!=NULL){ 
      token = strtok(NULL, delimiters); 
      if(!present(fIndex, token)){ 
       insert(fIndex, i+1,token); 
      } 
     } 
     i++; 
    } 
    fclose(file); 
} 

int strcmpigncase(char *s1, char *s2){/*checks words*/ 
    for(;*s1==*s2;s1++,s2++){ 
     if(*s1=='\0') 
      return 0; 
    } 
    return tolower(*s2)-tolower(*s2); 
} 

present(struct fileIndex* fIndex, char *findIt){/*finds if word is in structure*/ 
    struct fileIndex* current = fIndex; 
    while(current!=NULL){ 
     current = current -> next; 
     if(strcmpigncase(current -> str, findIt)==0){ 
      return current -> lineNum; 
     } 
    } 
    return 0; 
} 

void insert(struct fileIndex *head, int num, char *insert){/*inserts word into structure*/ 
    struct fileIndex* node = malloc(sizeof(struct fileIndex)); 

    node -> str = insert; 
    node -> lineNum = num; 

    node -> next = head; 
    head = node; 
} 

#define IN_WORD 1 
#define OUT_WORD 0 

int wordcount(FILE *input)/*number of words in file*/ 
{ 
    FILE *open = input; 
    int cur;   /* current character */ 
    int lc=0;  /* line count */ 
    int state=OUT_WORD; 
    while ((cur=fgetc(open))!=EOF) { 
     if (cur=='\n') 
      lc++; 
     if (!isspace(cur) && state == OUT_WORD) { 
      state=IN_WORD; 
     } 
     else if (state==IN_WORD && isspace(cur)) { 
      state=OUT_WORD; 
     } 
    } 
    return lc; 
} 

char *xerox(char *s){ 
    int i = strlen(s); 
    char *buffer = (char *)(malloc(i+1)); 
    if(buffer == NULL) 
     return NULL; 

    char *t = buffer; 
    while(*s!='\0'){ 
     *t=*s; 
     s++; t++; 
    } 
    *t = '\0'; 
    return buffer; 
} 
+1

코드를 들여 쓰고 코드를 문제가 있다고 생각되는 부분으로 줄이십시오. –

+4

gdb를 사용하는 것이 좋습니다. 프로그램을 실행하면 segfault가 발견 될 때마다 "bt"를 입력하십시오. 스택이 표시됩니다. – eyalm

+0

좋습니다. 모든 유능한 프로그래머는 궁극적으로 gdb와 같은 디버거를 사용하는 법을 배우기를 원할 것입니다. 차를 통과 할 수 있으며 사고의 줄 번호를 알려줍니다. 중단 점을 설정하고 값을 확인할 수도 있습니다. – hellork

답변

3

이 코드는 상당히 큰 문제가 있습니다. {

mainint하지 void 반환해야합니다 (** ARGV, INT의는 argc 문자를)

무효 메인 : 나는 아이디어를 제공하기 위해 단지 처음 몇 줄을 해부 것이다. 아마 당신의 문제를 일으키지는 않을 것이지만, 그렇지 않을 수도 있습니다.

file = fopen(argv[1],"r"); 

당신은 정말 argv[1]를 사용하기 전에 argc의 값을 확인해야합니다. 인수없이 프로그램을 호출하면 문제가 발생할 수 있습니다. 어떻게 호출했는지에 따라 문제의 원인이 될 수 있습니다.

struct fileIndex *fIndex = NULL; 

당신이 표시되지 않은 일부 헤더를 포함하지 않는 한,이 컴파일되지해야한다 - struct fileIndex 정의 된 것으로 보이지 않는다 (없으며 내가 볼 수 어디서나 정의 할 보인다 코드 게시).

delimiters = " .,;:!-";/*strtok chars to seperate*/ 
int wCount = wordcount(file);/*number of words in file*/ 

이 (wordcount)

는 파일의 끝으로 읽지 만 이후에 파일을 되감기하지 않습니다.

char **str[wCount+1];/*where the lines are being stored*/ 

귀하의 설명을 보면, 실제로 선 (복수형)을 저장할 필요가 전혀 없습니다. 당신이 원한 것은 하나의 라인을 읽고 토큰 화 한 다음 개별 토큰 (라인 번호와 함께)을 색인에 삽입하고 다음 라인을 읽는 것입니다. 당신이 말한 것에서 그러나, 한 번에 하나 이상의 원시 라인을 저장할 실제 이유가 없습니다.

int j=0; 
while(!feof(file)){/*inserting lines*/ 

위에서 언급했듯이 이전에 파일의 끝까지 읽었으며 결코 파일을 되 감은 적이 없습니다. 따라서 여기에 도착하자 마자 feof(file)true을 반환해야하므로이 루프 안의 어떤 것도 실행해서는 안됩니다./당신이 그것을 돌보는 경우,이 루프가 제대로 작동하지 않습니다 - 사실, 형태의 루프는 기본적으로 항상 잘못된 항상 while (!feof(file))입니다. 실패 읽으려고 할 때 루프를 종료 할 수 있도록 ...

while (1 == fscanf(file, "%1023s", line)) 

: 상황에서, 당신은 같은과, 당신의 fscanf의 결과를 확인하고 싶습니다. 여기에 무엇을 가지고

fscanf(file, "%s", &str[j]); 

는 악명 높은 gets 기본적으로 동일합니다 - 당신은 버퍼의 크기로 입력을 제한하는 것을 아무것도하지 않았다. 위에서 볼 수 있듯이 일반적으로 %[some_number]s을 사용하려고합니다. 여기에서 some_number은 사용중인 버퍼의 크기보다 하나 작습니다 (물론 필요하지는 않지만 버퍼도 필요합니다).

또한 줄 수를 할당 한 공간으로 제한하지 않았습니다 (단, 개별 줄과 같이 할당하지 않은 경우). 그러나, 당신의 설명에서 (위에서 언급했듯이) 어쨌든 둘 이상의 라인을 저장할 어떤 이유도없는 것 같기 때문에 나는 이것을 언급하는 것을 거의 망설이다.

또한 코드에는 malloc에 대한 호출이 있지만 아무 곳에서나 free에 대한 호출은 없습니다.

실제로 위의 조언 중 일부는 (결국에는 다소간) 잘못되었습니다. 개별 코드 행을 수정하는 방법을 살펴 보았지만 실제로는 코드를 일반적으로 조금 다르게 구성하려고합니다. 파일을 두 번 읽지 않고 한 번 단어를 집계하고 단어를 색인하기 위해 다시 읽은 다음 한 번에 한 줄씩 읽으려는 것입니다 (아마도 fgets을 사용하여 행을 단어로 분리하고 각 단어를 계산합니다 색인에 삽입하십시오 .Oh, 거의 확실하게 수행합니다. 아니요,은 색인에 연결된 목록을 사용하고 싶습니다. 트리 또는 해시 표를 사용하면 작업에 대한 의미가 더 커집니다.

또한이 코드에서 디버거를 사용하는 방향에 대한 제안에 동의하지 않습니다. 디버거는 코드가 현저하게 향상되지는 않을 것입니다. 현지화 된 문제 중 몇 가지를 찾을 수는 있지만 도움이되지는 않을 것입니다. 훨씬 더 나은 프로그램으로대신 필자는 실제로 사용해야하는 도구로 연필과 종이 조각을 제안합니다. 현재 문제는 주로 목표를 달성하기 위해 어떤 단계가 필요한지를 충분히 이해할 수 없을 정도로 문제에 대해 생각하지 않았기 때문에 발생합니다. 따라서 디버거는 그 질문에 대한 답을 찾는 데 많은 도움이되지 않습니다.

+0

감사합니다. 많은 조언을 받았고 seg 오류가 발생하지 않았습니다. (포함하지 않은 헤더 파일이 실제로있었습니다.) – Sams

2

당신이 좋은 디버거가 편리하지 않은 경우, 좋은 대체 당신이 할 수 있도록, 간단하게 코드를 통해 단계에서 몇 printf 문을 추가하는 것입니다 그것이 충돌하기 전에 얼마나 멀리 도착하는지보십시오. 이 코드

:

char **str[wCount+1];/*where the lines are being stored*/ 
int j=0; 
while(!feof(file)){/*inserting lines*/ 
    fscanf(file, "%s", &str[j]); 
    j++; 
} 

strchar *의 포인터 배열이다. 루프에서 입력의 각 부분을 슬롯에 읽어 들이고 있습니다. 몇 가지 문제가 있습니다.

  1. 나는 *의 대 &의 수의 카운트 오류 (나는 ;-) 그들에 대해 열심히 생각하는 것을 피하기 위해 포인터 간접 많은 수준하지 일반적으로 프로그램을 할 수 있다고 생각. &str[j]은 해당 배열 요소의 주소이지만 해당 배열 요소는 포인터에 대한 포인터입니다. 이제 포인터에 대한 포인터에 대한 포인터가 생겼습니다. 대신 char *str[wCount+1]이 있고 str[j]으로 읽으면 나는 그것이 일치 할 것 같아요. (또한 나는 fscanf을 많이 사용하지 않으므로 아마도 그것을 사용하는 것이 최선의 방법인지를 누군가가 확인할 수 있습니다.) 더 명확하게, 문자열 데이터에 실제로 메모리를 할당하지 않고 있습니다. 배열 자체에 대해서만 할당 할 수 있습니다. 각각에 대해 고정 된 금액을 할당하려고합니다 (각 fscanf 호출 전에 루프에서 수행 할 수 있습니다). 실제로는 fscanf이라는 문자가 고정 크기보다 보다 많아서을 읽을 수있어 다른 메모리 오류가 발생할 수 있습니다. 다시 말하지만,이 문제를 해결하려면 fscanf 전문가가 필요합니다.

희망이 있으면 시작하는 데 도움이됩니다. printf 제안이 실패한 코드에서 더 구체적인 지점을 찾으면 질문에 추가합니다.

+0

main 바로 다음에 print 문을 시도했지만 인쇄되지 않았습니다. 그게 무슨 뜻인지 모르거나 컴파일러가 seg 오류에 대해 아무 것도 출력하지 않는다면. – Sams

+1

흠, 아직 버퍼링 중이기 때문일 수 있습니다. 문자열의 끝에 \ n이 있습니까? 또한'fflush (stdout)'을 사용하여 강제로 시도하십시오. 그 함수를 입력하는 스택에 너무 많은 데이터가 있기 때문에 (예를 들어) 너무 길지 않을 가능성이 있습니다 (str과 같은 큰 로컬 배열을 찾아야합니다. (할당되지 않아야합니다.) 점은 아직 있습니다.) – Edmund

+1

'fprintf (stderr, ...')는 기본적으로 버퍼되지 않습니다. 일반적으로 큰 프로젝트에서는'__LINE__' 매크로를 넣고 DEBUG로 온/오프 토글합니다. 플래그. – hellork

관련 문제