2016-07-02 3 views
-3

문자열을 저장하기 위해 char 포인터로 scanf를 사용하려고합니다. ENTER 키 스트로크의 경우, 나는 그것을 붙잡고 싶다. 내가는 fgets를 사용할 수 있습니다 알고 있지만 나는 다음과 같은 코드를 작성하는 관리 그래서 가능하다면 알고 궁금 :scanf가 정규식 및 동적 할당에서 작동하지 않는 이유

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

int main(void) 
{ 
    char *string = NULL; 

    printf("Type anything : "); 

    scanf("%*[^\n]%10[^\n]ms", string); 

    printf("Your input : %s\n", string); 

    free(string); 

    return EXIT_SUCCESS; 
} 

을하지만 잘 작동하는 것 같다하지 않습니다. 출력은 다음과 같습니다.

문자열을 올바르게 표시하려면 어떻게해야합니까?

+1

1) Tehere 더 정규식없는 m 형식 지정자를 지원한다고 가정 코드에서 . 'scanf'는 그들을 지원하지 않습니다. 2) C에서 메모리 할당이 어떻게 작동하는지 배우십시오. 코드에 큰 오해가 있습니다. 3) 당신의 코드는 _undefined behaviour_를 호출합니다. (그것에 대한 serach!) – Olaf

+2

'scanf ("% * [^ \ n] % 10 [^ \ n] ms", 문자열);'->'scanf ("% m [ \ n] % * c ", & string);'와 glibc. – BLUEPIXY

+0

@BLUEPIXY 무슨 뜻인지 자세히 설명해 주시겠습니까? – Kusalananda

답변

0

scanf()의 형식 지정자 (변환, 실제로)는 허용되는 문자 범위 (또는 [^으로 시작하는 경우 거부 됨)를 지정합니다. 정규식이 아닙니다.

string을 고정 길이 배열로 선언하거나 malloc()을 사용하여 메모리를 할당해야합니다.

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

int main(void) 
{ 
     char string[100]; 

     printf("Type anything : "); 

     scanf("%99s", string); 

     printf("Your input : %s\n", string); 

     return EXIT_SUCCESS; 
} 

코드 다음의 변화는 동일한 작업을 수행하기위한 동적 배열을 사용

다음 변형 된 99 개 문자의 고정 길이 스트링 플러스 \0 (즉 100 char 긴) 종료 문자열을 사용 일 :

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

int main(void) 
{ 
     char *string; 

     string = malloc(100); 

     if (string == NULL) { 
       puts("Something went wrong"); 
       abort(); 
     } 

     printf("Type anything : "); 

     scanf("%99s", string); 

     printf("Your input : %s\n", string); 

     free(string); 

     return EXIT_SUCCESS; 
} 

는, C 유엔 유닉스 시스템에서 정규 표현식을 사용하는 regex.h 헤더에 선언 된 regcomp() 기능을 찾아 볼 수 있습니다.

+0

''% s.99 ''->''% 99 [^ \ n] "'(또는"% 99s "') – BLUEPIXY

+0

@BLUEPIXY 고마워,'% s.99'는'% .99s' (고정)이어야합니다. '% 99s'는 할당 된 버퍼가 오버플로되는 것을 허용하고,'% .99s'는 입력을 99 문자로 자릅니다. '% 99 [^ \ n]'은 (는) 버퍼 오버런과 같은 문제가 있으며, 줄 바꿈은 어떤 경우에도 문자열로 읽히지 않습니다. – Kusalananda

+1

답변을 주셔서 감사합니다. 정확히 내가 요구 한 바가 아니지만. 하지만 유용한 정보가 많이 있습니다. 정적 및 동적 할당 배열에 대해 이미 알고 있습니다. –

1

당신은 내가 당신의 문제가 읽을 수있는 첫 번째 문자가 \n 경우 %[^\n]이 실패 할 것입니다 설명하기 전에 알아야 할 첫 번째 일은.

지금 scanf("%*[^\n]%10[^\n]ms", string);이 무엇을 의미하는지 분석 할 수 있습니다 :

  1. %*[^\n]가 개행 문자까지 모든 것을 스캔하지만, 최종 \n에서 검색하지 않습니다.
  2. %10[^\n]ms 정말 당신이하지 생각하지 않습니다

    • 는 기억! %s%[은 두 가지입니다. 형식 지정자입니다. 후행 s이 아니며 %[ 지정자의 일부인이 아닙니다.
    • m의 위치가 잘못되었습니다. 그것은 개행 문자 또는 처음 발생하고,이 문자열을 저장할 수있는 충분한 메모리를 할당 중 최대 10 자, 때까지 모든 것을 스캔 %10m[^\n]해야 다음을 수정


    .

또 다른 버그가 mchar** 아닌 char* 그래서, 당신은 &string뿐 아니라 string을 공급해야 기대한다는 것입니다.

이제 위의 실수를 수정 한 후 scanf을 실행 해 보겠습니다.

  1. 실행이 scanfscanf에 도달 할 때까지 기다립니다.
  2. 123\n을 입력하십시오.
  3. %*[^\n]은 을 스캔하여 버리고 \n을 확인하고 \n을 사용하지 않고 스캔을 중지합니다.
  4. %10m[^\n]\n이고 입니다. 이유는 내 대답의 첫 문장에 나와 있습니다.
  5. scanf은 0을 반환하고 (아무 것도 스캔되지 않고 성공적으로 할당되었으므로) scanf이 실행을 완료합니다.
  6. printfstring이 여전히 NULL이기 때문에 (null)이 인쇄됩니다.

이제는 잘못된 점을 확인했습니다. 진짜 질문은이 작은 프로그램에 대해 scanf의 시작 부분에 %*[^\n]이있는 이유는 무엇입니까? 그것을 제거하면 모든 것이 예상대로 작동합니다!


제안 : 최종 \n와 함께 입력의 나머지는 (있는 경우) stdin 밖으로 튀어 미래는 문제가되지 않습니다 읽어 가도록 (듯이)

  1. scanfscanf("%*[^\n]"); getchar();를 추가합니다.
  2. scanf의 반환 값이 올바른지 확인하십시오. 그것이 무엇을 반환하는지 알기위한 RTFM.

고정 코드 (테스트되지 않은)

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

int main(void) 
{ 
    char *string = NULL; 

    printf("Type anything : "); 

    if(scanf("%10m[^\n]", &string) != 1) 
    { 
     fputs("Uh, oh! `scanf` failed! Exiting...\n", stderr); 
     return EXIT_FAILURE; 
    } 
    scanf("%*[^\n]"); 
    getchar(); 

    printf("Your input : %s\n", string); 

    free(string); 

    return EXIT_SUCCESS; 
} 

이 답변은 구현이

+0

고마워, 효과가 있었다. 내가 "사용자 유형 키를 바로 입력하십시오"와 같은 경우를 관리하고 싶다면 무엇을 제안 하시겠습니까? –

+0

좋은 질문입니다. if (scanf ("% 10m [^ \ n]", & string)! = 1) {if (getchar() == '\ n') {string = malloc (2); if (! string) {fputs ("어, 오! \'malloc \'실패, 종료 ... \ n", stderr); 반환 EXIT_FAILURE; } strcpy (string, ""); } else {fputs ("어, 오! \ scanf \'가 실패했습니다. 나가는 중 ... \ n", stderr); 반환 EXIT_FAILURE; } else if (string! = NULL) {scanf ("% * [^ \ n]"); getchar(); } else {puts ("EOF, exiting ..."); EOF를 반환하십시오. }'. 참고 :'strcpy'에'string.h'이 필요합니다. –

+0

경고 : 테스트되지 않은 코드 ↑ –