2014-10-24 7 views
0

콘솔에서 날짜를 가져 와서 월, 일 및 연도를 별도로 처리하려고합니다.C - Segmentation fault with strtok()

const size_t max = 11; 

void getDate(Date * d){ 
    char line[max]; 
    printf("\t Insert the date in the american format (mm/dd/yyyy): "); 
    fgets(line, max, stdin); 
    d->month = atoi(strtok(line, "/")); 
    d->day = atoi(strtok(NULL, "/")); 
    d->year = atoi(strtok(NULL, " ")); 
} 

한 번만 실행하면 오류가 발생하지 않습니다. 한 번에 2 개의 날짜를 얻으려고하면 세그먼트 오류 오류가 발생합니다.

Date d1, d2; 
getDate(&d1); 
getDate(&d2); 

나에게 오류를 범 라인 번째 실행시 d->day = atoi(strtok(NULL, "/"));이다.

+13

segfault는 메모리 누수가 아닙니다! –

+0

입력 내용은 어떻게됩니까? –

답변

3

문제는 fgets()을 사용하는 것입니다. 두 번째로 생각하는 것을 반환하지 않습니다.

처음으로 fgets()line[]"10/23/2014\0"으로 채우며 모두 양호합니다. 제 fgets()는 기다리지 않고 "\n\0"line[] 채워도록

그러나 두번째 통해 는 제 fgets()가 읽어 line[] 어떤 공간이 없어서stdin의 입력 버퍼에 여전히 입력 새로운 사용자 입력. 따라서 strtok(line, "/")에 대한 첫 번째 호출은 "\n" (atoi()이 0으로 변환 됨)을 반환하고 strtok(NULL, "/")에 대한 다음 호출이 실패하고 NULL을 반환하여 atoi()이 segfault가됩니다.

fgets()을 호출 할 때마다 읽혀집니다. 나는 또한 당신이 atoi(strtok()) 대신 sscanf()를 사용하는 것이 좋습니다 :

const size_t max = 16; 

void getDate(Date * d) 
{ 
    char line[max]; 
    printf("\t Insert the date in the american format (mm/dd/yyyy): "); 
    fgets(line, max, stdin); 
    if (sscanf(line, "%d/%d/%d", &(d->month), &(d->day), &(d->year)) != 3) 
     d->month = d->day = d->year = 0; 
} 

는 다른 방법으로, 확실히 날짜가 제대로 읽을 수 있도록 몇 가지 추가 검증을 추가 : 당신은 입력 버퍼에서 새 줄을 떠나

const size_t max = 16; 

void getDate(Date * d) 
{ 
    char line[max]; 
    int consumed; 
    printf("\t Insert the date in the american format (mm/dd/yyyy): "); 
    fgets(line, max, stdin); 
    while (1) 
    { 
     if (sscanf(line, "%d/%d/%d%n", &(d->month), &(d->day), &(d->year), &consumed) == 3) 
     { 
      if (consumed == strlen(line)) 
       break; 
     } 

     printf("\t Invalid input. Insert the date in the american format (mm/dd/yyyy): "); 
     fgets(line, max, stdin); 
    } 
} 
1

. 이는 어레이가 max 문자 만 사용하고 버퍼에 줄 바꿈 문자를 남기기 때문에 발생합니다.

어레이의 크기를 늘리거나 버퍼를 읽은 다음 버퍼를 지울 수 있습니다.

또한 모든 strtok() 호출에서 반환 값을 확인하여 호출이 성공했는지 감지해야합니다.