2013-01-23 2 views
0

초보자를 C로 사용. 문자열과 intsstruct의 다양한 필드에 입력되는 루프를 실행하려고합니다. '성'에 대한 프롬프트가 표시되면 사용자는 다른 입력없이 Enter 키를 눌러 루프를 종료해야합니다.fgets 및 sscanf를 정수로 사용하는 방법

문제는이 코드 루프 나던 말 (성과 이름 입력 요청이 동일한 라인에서 함께 실행) 및 급여에 대한 값으로 항상 밖으로 잘못 온다 (0 또는 일부 많은 수의)

입니다
while (employee_num <= 2) 
{ 
    printf("Enter last name "); 
    fgets(employee[employee_num].last_name, sizeof(employee[employee_num].last_name), stdin);     

    if(strlen(employee[employee_num].last_name) == 0) 
     break; 

    printf("Enter first name "); 
    fgets(employee[employee_num].first_name, sizeof(employee[employee_num].first_name), stdin); 

    printf("Enter title "); 
    fgets(employee[employee_num].title, sizeof(employee[employee_num].title), stdin); 

    printf("Enter salary "); 
    fgets(strng_buffer, 1, stdin); 
    sscanf(strng_buffer, "%d", &employee[employee_num].salary);  
    ++employee_num; 
    getchar(); 
} 

대신이 코드를 사용하면 루프를 처음 실행 한 후에 루프를 종료 할 수 있지만 그 후에 끝낼 수는 없습니다 (성 부분에서 Enter 키를 눌러서 \ n 할 수 없습니다. ?) :

char strng_buffer[16]; 
while (employee_num <= 5) 
{ 
    printf("Enter last name "); 
    fgets(strng_buffer, sizeof(strng_buffer), stdin);     
    sscanf(strng_buffer, "%s", employee[employee_num].last_name);  

    if(strlen(employee[employee_num].last_name) == 0) 
     break; 

    printf("Enter first name "); 
    fgets(strng_buffer, sizeof(strng_buffer), stdin); 
    sscanf(strng_buffer, "%s", employee[employee_num].first_name); 


    printf("Enter title "); 
    fgets(strng_buffer, sizeof(strng_buffer), stdin); 
    sscanf(strng_buffer, "%s", employee[employee_num].title); 

    printf("Enter salary "); 
    scanf("%d", &employee[employee_num].salary);   
    ++employee_num; 
    getchar(); 
} 

이 작품을 만드는 방법에 대해 궁금합니다. 의도 한대로 그리고 이것과 같은 항목에 대한 모범 사례 (예 : sscanf, fgets 등 사용)

미리 감사드립니다!

답변

1

Abhijit에서 언급 한 수정을 가정 할 때 왜 첫 번째를 두 번째로 변환합니까? sscanf이 추가되었으므로 두 번째 동작이 첫 번째 동작과 다르게 동작한다는 사실을 알고 있습니까?귀하의 의도가 첫 번째를 단축하는 것이라면, 두 번째 것은 상당히 부피가 큰 것처럼 보입니다. 상황에 sscanf을 추가하는 대신 struct employee *e = employee + employee_num;을 선언하고이를 반복적으로 사용하여 employee[employee_num] 대신 첫 번째 문자를 줄이면 어떨까요?

fgets에 관한 "모범 사례"는 반환 값을 확인하는 것입니다. EOF을 만날 경우 fgets이 무엇을 반환 할 수 있다고 가정합니까? 성공하면 fgets이 무엇을 반환 할 것이라고 생각합니까?

scanf에 관한 "모범 사례"는 반환 값을 확인하는 것입니다. scanf의 반환 값에 관해서, 나는 조심스럽게 this scanf manual을 읽고 다음 질문에 대답 제안 :

  1. int x = scanf("%d", &employee[employee_num].salary); 당신이 내가 입력으로 "fubar\n"를 입력하면 x이 될 것입니다 생각합니까?
  2. ("fubar\n")은 어디로 갈 것이라고 생각하십니까?
  3. ungetc의 경우 stdin으로 돌아 가면 다음 직원의 성은 무엇입니까?
  4. int x = scanf("%d", &employee[employee_num].salary);x이 코드를 Windows에서 실행하고 Ctrl + Z를 눌러 EOFstdin으로 보내면 어떻게 될까요?
  5. int x = scanf("%d %d", &y, &z);x이 무엇이겠습니까? scanf은 두 개의 변수 yz에 성공적으로 값을 넣었습니까?

P. EOF은 Windows에서 CTRL + Z를 사용하여 stdin을 통해 전송할 수 있으며, Linux 및 CTRL + D를 사용하여 친구와 다른 프로그램 및 파일의 입력을 리디렉션 할 수 있습니다.

+0

감사합니다! 이러한 질문을 통해 scanf()를 사용할 때 어떤 일이 벌어지고 있는지 훨씬 잘 이해할 수있었습니다. 내가 틀렸다면 나를 정정하십시오. 그렇지만 배열에 stdin을 쓰고 sscanf()를 사용하여 int 값을 변수에 다시 읽을 수 있습니까? – Gitarooman

+0

예, fgets와 sscanf는 그런 식으로 작동합니다. % s 형식 지정자는 sscanf에 * 단어 * (예 : 0 개 이상의 공백이 아닌 문자를 첫 번째 공백까지)를 복사하도록 알려줍니다. 나머지 fgets'd 라인은 어떻게됩니까? 이것은 귀하의 두 번째 게시물이 귀하의 첫 번째 게시물과 다른 하나의 방법입니다. – Sebivor

2

루프는 break 문

if(strlen(strng_buffer) == 0) 
     break; 

을 초기화되지 않은 문자 버퍼 strng_buffer가 발생했을 때 우연히 조기에 중단 난 당신이

의도 한 생각되는 0

를 반환하는 strlen를 일으키는 첫 번째 문자로 널 (null)이있다

if(strlen(employee[employee_num].last_name) == 0) 
      break; 

은 루프 종결 자로, 조기에 루프가 종료되는 원인이 될 수 있습니다.

+0

정확합니다 (약간 피곤합니다). 내 시도에서 더 많은 코드를 보여주는 편집을 만들었습니다. 나는 아직도 제대로 작동하기 위해 어느 하나를 얻을 수 없습니다. 누군가가 fgets()와 sscanf()를 사용하여 급여에 대한 int 부분을 읽었지만 내 검색에서이를 수행 할 명확한 방법을 찾을 수 없었습니다. 사실 실용적인 옵션입니까? – Gitarooman

1

fgets은 줄 바꿈 (\n)이 포함 된 문자열을 반환하는 것이 문제입니다. 따라서 사용자가 정보를 입력하지 않고 return 키를 눌러도 문자열은 비어 있지 않습니다. 또한 salary의 버퍼 크기가 너무 작습니다.

그래서, 어느 쪽이든 당신의 모든 fgets\n을 제거 또는 당신이 수표를 변경 : 또한

if(strlen(employee[employee_num].last_name) == 1) break; 

당신이 버퍼를 받고있을 때,

fgets(strng_buffer, 10, stdin); 
처럼, 더 큰 뭔가 일을 변경

employee[employee_num].last_name[strlen(employee[employee_num].last_name)-1] = 0; 
: 각는 fgets에서 \n을 제거 할 경우

그러나, 당신은 뭔가를 할 수 있습니다

모든 문자열에 대해이 작업을 수행 할 수 있으며, 더 나은 방법으로 모든 문자열에 대해 수행 할 수 있습니다.

EDIT : 입력 할 때마다 사용자가 Enter 키를 누를 것을 보장 할 수 있다면 안전하게 가정 할 수 있습니다. 그러나 항상 그런 경우가 아니라면 마지막 문자가 \n이 아니므로이 방법으로 제거하면 문제가 발생할 수 있습니다.

+0

fgets가 항상 줄 바꿈으로 문자열을 반환하지는 않습니다. 나는 e-> last_name [strcspn (e-> last_name, "\ n")] = '\ 0'을 제안한다. '\ n'이없는 경우를 처리하려면 제안을 통해 유용한 문자가 삭제되고 버그가 발생합니다. – Sebivor

+0

그래,하지만 나는 사용자가 엔터를 눌러서 (그리고 EOF가 없을 것이라고 가정하는) 상황에 집중했다. 'strlen'이 0을 반환 할 수 있기 때문에 1을 빼는 것은 위험합니다. 나는 모든 것을 기록하기 위해 주석을 갱신 할 것입니다. – pldoverflow

+0

char strng_buffer [10]; fgets (strng_buffer, 10, stdin); fgets가 '\ n'에 도달하기 전에 9 바이트를 읽는 것은 어떻습니까? – Sebivor