2011-02-08 3 views
3

이것은 주어진 숙제를 숙제하기위한 것입니다. 사용자가 scanf으로 정렬하려는 문자열의 수를 묻는 메시지를 표시하고 해당 숫자를 기반으로 배열을 할당 한 다음 fgets으로 문자열 자체를 가져옵니다.scanf와 fgets에 관한 문제

문자열 수가 하드 코드 된 경우 모두 작동하지만 사용자가 나사를 결정할 수 있도록 scanf이 추가됩니다.

#include <assert.h> 
#include <stdio.h> 
#include <stdlib.h> 

#define LENGTH 20 // Maximum string length. 

int main(void) 
{ 
    int index, numStrings = 0; 
    char **stringArray; 
    printf("Input the number of strings that you'd like to sort: "); 
    assert(scanf("%d", &numStrings) == 1); 
    stringArray = (char **)malloc(numStrings * sizeof(char *)); 

    for (index = 0; index < numStrings; index++) 
    { 
     stringArray[index] = (char *)malloc(LENGTH * sizeof(char)); 
     assert(stringArray[index] != NULL); 
     printf("Input string: "); 
     assert(fgets(stringArray[index], LENGTH, stdin) != NULL); 
    } 

    // Sort strings, free allocated memory. 

    return 0; 
} 

을 그리고 여기처럼 콘솔 보이는 내용은 다음과 같습니다 : 여기에 코드는이 배열의 시작 부분에 빈 문자열의 결과로, 루프의 첫 번째 반복 건너 뜁니다

 
Input the number of strings that you'd like to sort: 3 
Input string: Input string: foo 
Input string: bar 

. 제 질문은, 왜 그렇게하는지, 어떻게 해결할 수 있습니까? 그래서

 
Input the number of strings that you'd like to sort: 3 
foo 
Input string: Input string: bar 
Input string: baz 

, 내가 입력, 문자열을 모두 할 수 있지만 문자열에 대한 첫 번째 메시지가 잘못된 위치에 있습니다 : 여기


콘솔이 scanf에 전달 된 형식 문자열 "%d\n"으로 보이는거야 . 는 AS [맞은 버튼을 입력 할 때에서]

scanf("%d\n", &numStrings) 

없이, scanf와는 잔류 개행 문자를 읽습니다 :

+4

사용자 입력을 읽는 입력 기능과 같이 실패 할 것으로 예상되는 기능에 대해 'assert()'를 수행하지 마십시오. 오류를 무시하는 것보다 낫습니다. 오류를 온전하게 처리하는 것만 큼 좋지 않습니다. –

+0

@Jonathan 조언을 주셔서 감사합니다. – gdejohn

답변

3

실제 대답은 (내 겸손하지만 절대적으로 올바른 의견 : P) scanf을 사용하지 않는 것입니다. fgets을 사용하여 첫 번째 줄 (예 : 숫자)을 읽고 나서 sscanf 또는 strtoul 등의 문자열을 직접 구문 분석하십시오. 그렇게하면 누군가가 좋은 형식으로 데이터를 입력하지 않을 때 오류를 처리 할 수 ​​있고 scanf의 강력한 공백 처리가 해킹되지 않아도됩니다.

또한 길이가 -4 인 배열이 많지 않을 경우 크기를 저장하기 위해 int을 사용하지 마십시오. 표준에서는 객체 크기 및 배열 인덱스를 저장할만큼 큰 부호없는 유형 size_t을 부호없는 유형으로 지정합니다. 다른 유형을 사용한다고해서 작동이 보장되는 것은 아닙니다.

+0

int를 사용하여 크기를 저장하지 않는다고 말할 때 내 코드에서 어떤 부분을 언급합니까? – gdejohn

+0

@Charlatan -'numberOfStrings' 특별히, 당신이'malloc'에 전달한 모든 것은'strlen'에서 받거나 배열을 색인하기 위해'size_t'이어야합니다. –

+0

그렇다면'stdin'에서'malloc'을 전달하기 위해'size_t'라는 타입을 얻을 것을 어떻게 추천합니까? int를 파싱하고 캐스팅합니까? 나는 (atoi로 사용되는) 그대의 대답을 가지고 갔다. 그리고 이제는 잘 작동한다. – gdejohn

6

당신은 scanf와에 \ n을으로 바꾸어 \ n을 소지품 scanf와 말할 필요 루프의 첫 번째 줄

+1

Foo Bah의 대답에 추가 할 몇 가지 덧글 : 코드에서 한 가지 문제는'assert' 내부에 부작용이 있으면 안됩니다. 'assert' 내부의 것들은 해제 모드에서 실행되지 않습니다. 'printf' 다음에'fflush (stdout);'를 넣어서 사용자가 입력을 요청하기 전에 프롬프트가 출력되도록 할 수 있습니다. –

+0

또한 문자열이 너무 길지 않으면 fgets에 종료 줄 바꿈 문자가 포함됩니다. –

+0

문자열이 너무 길면'fgets()'는 다음 번 호출에서 읽을 행의 나머지 문자를 그대로 둡니다. 표준 I/O 기능 중 하나. –