2009-11-29 5 views
5

나는 '50'문자 수 인과는 - 사용자가 문자열의 내용을 입력하면

char mystring[50]; 

, 당신은 문자열과 다음과 같은 문자 수를 선언 할 수 있습니다 C 알고있는 .

그러나 사용자가 문자열의 내용을 입력하려는 경우 (scanf ("% s", mystring);) 적절한 절차는 무엇입니까?

char mystring[0]; 

나는 사용자가 얼마나 많은 문자를 입력 할 것인지 실마리가 없으므로 '0'으로 남겨두고 있습니까?

또는 내가 할,

char mystring[400]; 

를 입력하는 사용자에 대한 400 자까지 포기?

답변

6

scanf()와 % s의 정확한 문제에 부딪혔습니다. 얼마나 많은 입력이 있는지 모르면 어떻게됩니까?

char mystring[0];을 실행하면 프로그램이 올바르게 컴파일됩니다. 그러나 당신은 항상 segfault 것입니다. 크기가 0 인 배열을 만들므로 배열에 을 넣으려고하면 배열에 즉시 할당됩니다 (메모리가 할당되지 않으므로 문자열 범위를 벗어납니다) - segfault입니다.

그래서 1 점 : 항상 문자열의 크기를 할당해야합니다. char *mystring 대신에 char mystring[0]라고 말하고 싶은 상황은 거의 없습니다 (알 수 없음, 전혀 없음).

다음으로 scanf를 사용할 때 "% s"지정자를 사용하지 않으려합니다. 문자열의 크기를 경계 검사하지 않기 때문입니다. 그래서 당신이 경우에도 :합니다 (512th이 \ 0 때문에) 사용자가 넘는 511 개 문자를 입력

char mystring[512]; 
scanf("%s", mystring); 

경우, 당신은 당신의 배열의 범위 밖으로 이동합니다.이를 해결하는 방법은 다음과 같습니다

scanf("%511s", mystring); 

이 모두 C 당신이 기대하는 것보다 더 많은 입력이있는 경우 자동으로 문자열의 크기를 조정하는 기능이 없다는 말을하는 것입니다. 이것은 수동으로해야 할 일입니다.

이 문제를 처리하는 한 가지 방법은 fgets()을 사용하는 것입니다.

당신은 말할 수 :

while (fgets(mystring, 512, stdin)) 
{ 
    /* process input */ 
} 

그런 다음 4 자 후 길이 5의 문자열로, mystring

위의 코드를 사용해보십시오 구문 분석 sscanf를()를 사용할 수 있습니다 읽은, 그 코드 나머지 입력을 검색하기 위해 다시 반복합니다. "처리 중"은 문자열을 더 큰 크기로 재 할당 한 다음 fgets()에서 최신 입력을 추가하는 코드를 포함 할 수 있습니다.

위의 코드는 프로그램 루프를 만들고 무한 문자열 길이를 처리하므로 내부 하드 제한이 필요합니다 (예 : 최대 10 회 루프).

+0

% s은 (는) 전체 문자열이 아닌 단어를 읽도록 추가되어야합니다. scanf 형식 문자열은 공백과 개행 문자를 구분 기호로 사용하기 때문입니다.이 경우, 대신에 % c를 사용하십시오 (필드 너비와 함께) 또는 fgets를 사용하십시오. 필드 너비가있는 % c의 경우 전체 버퍼 문자열을 0으로 초기화해야합니다. –

+0

프로그램이 항상 segault되지는 않습니다. 실제로, 아마 대부분의 시간. 프로그램이 자동으로 중단됩니다. 사랑스러운 C가 아닌가요? :-) –

2

사용자는 항상 더 많은 문자를 입력 할 수 있으므로 버퍼가 넘치게됩니다 (보안 취약점의 공통 원인). 당신은, 그러나,과 같이,을 scanf하기 위해 "필드 폭"을 지정할 수 있습니다

scanf("%50s", mystring); 

이 경우 귀하의 버퍼가 50 문자 필드 플러스 null 종결을 고려하여, 51 자한다. 또는 버퍼를 50 자로 만들고 scanf에 너비를 지정하십시오.

+0

문자열을 선언 할 때 '0'또는 큰 숫자를 지정해야합니까? – HollerTrain

+1

이 예제에서는 51 이상을 지정해야합니다. (널 종결 자의 길이는 1입니다.) – Thanatos

+0

ok. 문자열을 적절한 코딩이 아니라고 선언 할 때 '0'으로 표시할까요? 내 문제는 내가 얼마나 많은 사용자가 입력하지만 동시에 정확한 방법을 배우고 싶지는 모르겠다 ... – HollerTrain

2

표준 C 라이브러리의 일부가 아닌 ggets()라는 함수가 있습니다. 아주 간단한 기능입니다. malloc()을 사용하여 문자 배열을 초기화합니다. 그런 다음 한 번에 한 문자 씩 stdin에서 문자를 읽습니다. 그것은 얼마나 많은 문자가 읽혔는지 추적하고, 공간이 부족할 때 realloc()을 사용하여 문자 배열을 확장합니다.

이 여기에 있습니다 : 당신이 코드를 읽고 다시 구현 자신을 제안 http://cbfalconer.home.att.net/download/index.htm

.

0

C에서 평소 연습 GNU readline 혹은 NetBSD editline, aka libedit. 같은 것을 사용하는 것입니다 (같은 API, 다른 구현 및 소프트웨어 라이센스를.) 간단한 또는 숙제 프로그램

, 당신은 이론을 scanf 할 필드 폭을 줄 수 , 더 일반적인 방법은 고정 너비 배열에 fgets()을 연결 한 다음 sscanf()을 실행하는 것입니다. 이렇게하면 읽는 줄 수를 제어 할 수 있습니다.

0

예를 들어 사용자가 이름을 입력하는 경우 일부 사람들이 실제로 긴 이름을 가지고 있기 때문에 'mystring'의 크기를 35 자로 늘리는 것이 안전하지 않을 수 있습니다. 사용자가 요청한 정보를 입력 할 수없는 경우에 도달하고 싶지 않습니다. 이를 수행하는 올바른 방법은 사용자가 입력 할 수있는 모든 입력을 처리 할 수있는 매우 큰 크기의 임시 버퍼를 만드는 것입니다. 사용자가 정보를 입력하고 버퍼에 저장되면 버퍼의 끝에있는 모든 여분의 공간을 잘라내면서 버퍼에서 문자를 미스 트 링으로 전송합니다. 당신은 'mystring'을 위해 필요한 크기를 정확하게 말할 수있을 것이고, 그 공간만큼 malloc하고 버퍼를 버릴 수 있습니다. 이렇게하면 나머지 프로그램에 더 많은 메모리를 사용하는 문자열을 사용하지 않고 ... 필요한 메모리 양의 문자열 만 사용할 수 있습니다.

+0

사용자가 입력하는 것이 매우 드문 경우에 할당 된 버퍼보다 ​​크지 않은지 또는 누군가가 프로그램을 악용하려고 시도 할 때 어떤 종류의 검사를해야합니다. –

1

이 cbfalconer의 몇 가지 약간의 수정과 코드 (http://cbfalconer.home.att.net/download/index.htm)와 하나 개의 파일로 컴파일입니다 :

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include "ggets.h" 

#define INITSIZE 112 /* power of 2 minus 16, helps malloc */ 
#define DELTASIZE (INITSIZE + 16) 

enum {OK = 0, NOMEM}; 

int fggets(char* *ln, FILE *f) 
{ 
    int  cursize, ch, ix; 
    char *buffer, *temp; 

    *ln = NULL; /* default */ 
    if (NULL == (buffer = malloc(INITSIZE))) return NOMEM; 
    cursize = INITSIZE; 

    ix = 0; 
    while ((EOF != (ch = getc(f))) && ('\n' != ch)) { 
     if (ix >= (cursize - 1)) { /* extend buffer */ 
     cursize += DELTASIZE; 
     if (NULL == (temp = realloc(buffer, (size_t)cursize))) { 
      /* ran out of memory, return partial line */ 
      buffer[ix] = '\0'; 
      *ln = buffer; 
      return NOMEM; 
     } 
     buffer = temp; 
     } 
     buffer[ix++] = ch; 
    } 
    if ((EOF == ch) && (0 == ix)) { 
     free(buffer); 
     return EOF; 
    } 

    buffer[ix] = '\0'; 
    if (NULL == (temp = realloc(buffer, (size_t)ix + 1))) { 
     *ln = buffer; /* without reducing it */ 
    } 
    else *ln = temp; 
    return OK; 
} /* fggets */ 
/* End of ggets.c */ 

int main(int argc, char **argv) 
{ 
    FILE *infile; 
    char *line; 
    int cnt; 

    //if (argc == 2) 
     //if ((infile = fopen(argv[1], "r"))) { 
     cnt = 0; 
     while (0 == fggets(&line, stdin)) { 
      fprintf(stderr, "%4d %4d\n", ++cnt, (int)strlen(line)); 
      (void)puts(line); 
      free(line); 
     } 
     return 0; 
     //} 
    //(void)puts("Usage: tggets filetodisplay"); 
    //return EXIT_FAILURE; 
} /* main */ 
/* END file tggets.c */ 

나는 그것을 테스트하고 항상 당신이 원하는 걸 줄 것입니다.

+0

기본적으로 원래 코드를 얻으려면 주석을 주석 처리하고 fggets 호출에서 stdin을 infile로 바꿉니다. –

관련 문제