2014-11-27 2 views
0

나는 꿈의 자동차, 차고 목록, 차량 목록을 저장하는 텍스트 파일을 만들 수 있도록 프로그램을 작성하고 있습니다. 나는 fgets와 sscanf를 사용하여 사용자에게 make, then, then, then, value, then color를 물어 보았다. 그러나 어떤 이유로 모델을 가져 오는 사용자 입력 단계를 건너 뛰고 값을 묻는 것으로 점프하지만 여전히 값을 입력하기 위해 printf 위에 "자동차 모델 입력 :"의 printf를 표시합니다. 아래 코드는 내 fgets/sscanf 함수를 포함하고있는 코드에서 발췌 한 것입니다. 출력의 예가 될 것이므로 내 설명이 명확하지 않은 경우 문제가 무엇인지 볼 수 있습니다.프로그램 fgets 및 sscanf를 사용하여 사용자 입력 기회를 건너 뜁니다.

if (!listappend){ 
    printf("File nonexistent/inaccessible."); 
    return 1; 
} 
    memset(colorin, 0, sizeof(colorin)); 
    memset(makein, 0, sizeof(makein)); 
    memset(modelin, 0, sizeof(modelin)); 
    memset(yearin, 0, sizeof(yearin)); 
    memset(valuein, 0, sizeof(valuein)); 


    printf("\nEnter car make: "); 
    fgets(makein, sizeof(makein), stdin); 
    sscanf(makein, "%[^\n]",makein); 
    fprintf(listappend, "\n%s", makein); 
    printf("\nEnter car manufacture year: "); 
    fgets(yearin, sizeof(yearin), stdin); 
    sscanf(yearin, "%d", &yearinf); 
    printf("\nEnter car model: "); 
    fgets(modelin, sizeof(modelin), stdin); 
    sscanf(modelin, "%[^\n]",modelin); 
    fprintf(listappend, "\n%s", modelin); 
    printf("\nEnter approximate car value: $"); 
    fgets(valuein, sizeof(valuein),stdin); 
    sscanf(valuein, "\n%f", &valueinf); 
    fprintf(listappend, "\n%d %'.2f", yearinf, valueinf); 
    printf("\nEnter car color: "); 
    fgets(colorin, sizeof(colorin), stdin); 
    sscanf(colorin, "%[^\n]",colorin); 
    fprintf(listappend, "\n%s", colorin); 

    fclose(listappend); 

샘플 출력 : 당신이 볼 수 있듯이

|-|-|-|-|-|-|-|-|-|-|Car-lection List|-|-|-|-|-|-|-|-|-|-| 
---------------------------------------------------------- 
[A]dd New Car     [V]iew List 
[M]enu       [D]eveloper Info 
[C]lear List  [Q]uit 

Option? 
A 

Enter car make: Honda 

Enter car manufacture year: 2000 

Enter car model: 
Enter approximate car value: $5000 

Enter car color: Blue 

Option? 
V 
    Entry Year Color Make Model Color Approx. Value 
    1| 2000 Blue Honda, approximate value: $5,000.00 

, 사용자는 입력에 자동차 모델 수 있어야하지만, 프로그램이 바로 입력 할 수있는 기회를 건너 뛰는, 대략 차 값을 요청합니다 자동차 모델 정보. 그리고 여기가 car_list.txt의 고양이, 텍스트 파일은 내가 읽을 수 있도록하기 위해 문자열과 값을 저장 :

cat car_list.txt 

    Honda 


    2000 5,000.00 
    Blue 

그것이 내가 낭비에 대해 사과 바보 같은 실수 그래서 만약 내가 C 프로그래밍에 새로 온 당신 시간, 그러나 그것은 나를 미치게했다. 당신의 도움에 미리 감사드립니다! sscanf()

+0

형식 문자열이 줄 바꿈 문자로 끝나지 않으므로 위의 모든'printf()'호출 바로 다음에'fflush (stdout)'이 필요합니다. 그리고 입력을 요청하기 전에 프롬프트를 보지 못할 수도 있습니다. –

+0

코드가 완전하지 않지만 sscanf (modelin, "% [^ \ n]", & modelinf)를 의미합니까? 세 번째 매개 변수를 참고하십시오 ... –

+2

'sscanf (makein, "% [^ \ n]", makein);와 같은 것들 또한 매우 의심 스럽습니다. 스캔중인 문자열과 동일한 문자열을 쓰고 있습니다. 여기서 수행하면 안됩니다. C99 이상에서는 형식 문자열을'restrict'로 한정합니다. 이것은 다른 포인터를 통해 해당 객체에 액세스하는 정의되지 않은 동작을 의미합니다. 여기에서 수행중인 작업입니다. –

답변

2

호출이 올바르지 않습니다 :

sscanf(makein, "%[^\n]", makein); 

이 정의되지 않은 동작에 이르게.

int sscanf(const char *restrict s, const char *restrict format, ...); 

restricts 인수의 별칭입니다 sscanf()에 대한 호출에서 다른 매개 변수가 없을 수 있다는 것을 의미한다 (또는 그와 겹치는 : sscanf()에 대한 공식적인 POSIX (및 C99, C11) 사양입니다 그것). 코드에서 소스 문자열과 대상 문자열로 makein이 있는데 이는 restrict 기준을 위반하므로 정의되지 않은 동작이 발생합니다.

코드를 반복해서 사용하면 기능을 사용할 수 없습니다.

정의한 문자열의 크기가 표시되지 않았습니다. fgets()이 성공했는지 또는 sscanf()도 성공했는지 결코 확인한 적이 없습니다. 내 의심은 문자열 중 하나가 너무 짧아서 fgets()이 실제로 전체 라인을 읽지 않으며 '건너 뛴'이 이전 라인의 마지막 부분을 읽는다는 것입니다. 입력 데이터를 인쇄하여 진단 할 수 있습니다. 예를 들어, 각 (성공) fgets() 후에는 인쇄 할 수 있습니다

printf("<<%s>>\n", makein); 

프로그램이 당신이 볼 것으로 예상 입력 보았다 보장되는 - 디버깅 기술의 가장 기본 중 하나. 그래서


내가 설정에뿐만 아니라 세 번째로 첫 번째 매개 변수를 반복 각 sscanf에 대한 새로운 변수를 필요로 말을하는지? 내가 말하려고하는 것의 전 : sscanf(makein, "%[^\n]", makein)이 아닌 sscanf(makein, "%[^\n]", &makeins)?

다소 많습니다.

해결해야 할 두 가지 문제가 있습니다. 하나는 원래 sscanf()으로 전화하면 정의되지 않은 동작이 발생한다는 것입니다. 또 다른 부분은 각 라인의 데이터가 변수에 들어간다고 가정한다는 것입니다. 크기를 표시하지 않았으므로 그것이 그럴듯한지를 알기가 어렵습니다. 또한 모든 필드가 같은 크기인지 여부는 확실하지 않습니다. 내 가정은 그들이 다른 크기의 것입니다.

여기에는 몇 가지 방법이 있습니다. 나는 아마의 라인을 따라 함수를 써서 :

int read_value(const char *prompt, char *buffer, size_t buflen) 
{ 
    char line[4096]; // Big! 

    buffer[0] = '\0'; // Null terminate output in case of EOF. 
    printf("%s: ", prompt); 
    fflush(stdout); // Optional 
    if (fgets(line, sizeof(line), stdin) == 0) 
     return EOF; 
    size_t len = strlen(line); 
    if (line[len-1] == '\n') 
     line[--len] = '\0'; 
    if (len > buflen) 
     len = buflen - 1; 
    memmove(buffer, line, len); 
    buffer[len] = '\0'; 
    return len; 
} 

이 데이터의 절단이 OK라고 가정하고, 공백을 선도 생략, 나 줄 바꿈 이외의 공백을 후행 될 필요하지 않습니다. 선행 공간을 제거하는 것은 간단합니다 : strspn()이 이상적입니다. 후행 공백을 제거하는 것은 그리 간단하지 않습니다. 모든 빈 줄을 올바르게 처리하도록 신경을 쓰면서 줄이기 루프를 작성해야합니다.

이 함수는 프롬프트 문자열을 출력하고 끝에 콜론과 공백을 추가합니다. 원하지 않는 경우 printf("%s", prompt); 또는 fputs(prompt, stdout); 만 사용하십시오. printf(prompt);을 사용하지 마십시오. 예를 들어, 프롬프트에 백분율 기호 (예 : "Enter discount (%)")가 포함되어 있으면 끔찍한 충돌이 일어나기 때문입니다. 일반적으로 fflush()은 필요하지 않지만 (일반적으로 시스템에서 처리합니다) 프롬프트가 표시되는지 확인합니다.

fgets()은 큰 라인 버퍼를 읽습니다. 모든 실질적인 목적을 위해, 그것은 당신이 전체 라인을 읽을 수 있도록합니다. 줄 바꿈 테스트에는 잘린 줄을 처리하는 else 절을 사용할 수 있습니다. JSON 데이터 (예 : 북마크 파일)는 엄청난 양의 단일 데이터가 될 수 있습니다. 줄을 끝내거나 오류를보고 할 수 있습니다. 또는 다른 어떤 메커니즘이 당신에게 적합한 지 알 수 있습니다.

코드는 함수에 전달 된 버퍼에 맞지 않을 경우 읽은 데이터를 자릅니다. 다시 원할 경우 오류를보고하거나 간단히 데이터를 덮어 쓰는 것보다 정교한 잘림 알고리즘을 사용할 수 있습니다 최대 길이 (예 : 이전 단어 분리 검색)에서.

memmove()에 null을 더한 값은 복사 후에 데이터를 종료합니다. 문자열의 길이가 리턴됩니다 (또는 오류시 EOF). 이것은 fgets()의 더 나은 버전이 자동으로 수행하는 기능입니다 (POSIX getline() 기능이 이미 수행함). 이 기능을 사용

, 읽는 코드 :

printf("\nEnter car make: "); 
fgets(makein, sizeof(makein), stdin); 
sscanf(makein, "%[^\n]",makein); 

이 될 것입니다 :

if (read_value("\nEnter car make", makein, sizeof(makein)) == EOF) 
    …handle error… 

기존 코드는 EOF를 무시, 그래서 이것은 개선이다. 나는 또한 귀하의 memset() 전화가 실제로 필요하지 않습니다; 돌려 주어지는 캐릭터 라인은 null로 종료됩니다.

+0

그럼 첫 번째 매개 변수를 세 번째 매개 변수로 반복하는 각 sscanf에 대해 새 변수를 설정해야한다고 말하는 것입니까? 나는 sscanf (makein, "% [^ \ n]", makein) 대신 sscanf (makein, "% [^ \ n]", & makeins)를 사용하려고합니다. –

+0

Oh 및 각 char 배열은 #DEFINE으로 설정되어 64 개 요소를 보유합니다. 이제는 sscanf (makein, "%^\ n", & makeins)를 사용하여 5 가지 필드 모두에 대한 데이터를 입력 할 수있게되었지만, 이제는 마지막 입력 필드를 입력 한 후 즉시 프로그램을 종료합니다. if 자동차 모델은 몇 문자 이상입니다. –

+0

오, 와우, 정말 고마워, 너는 나를 돕기 위해 많은 일을했고, 나는 그것을 크게 고맙게 생각한다. 당신의 대답은 내 머리 위로 조금이지만, 나는 그것을 배우기 위해 최선을 다할 것입니다. –

관련 문제