2016-11-11 31 views
6

Próbuję odczytać ciąg znaków, który może ale nie musi zawierać spacji ex. "Witaj świecie". Wykonując następujące czynności z menu wyboru liczby, które jest wprowadzane przez użytkownika. To tylko mała replika tego, co próbuję zrobić.Czytanie w ciągu znaków ze spacjami w C

#include <stdio.h> 
#include <string.h> 

int main(void){ 
    char line[3][80]; 

    strcpy(line[0],"default line 1\n"); 
    strcpy(line[1],"default line 2\n"); 
    strcpy(line[2],"default line 3\n"); 

    for(int i = 0; i < 3; i++){ 
    printf("%s", line[i]); 
    } 

    int option = 0; 
    printf("would you like to replace line 1? (1 for yes)\n"); 
    scanf("%d",&option); 
    if(option==1){ 
    printf("what would you like to replace the line with?\n"); 
    fgets(line[0],strlen(line[0]),stdin); 
    } 

    for(int i = 0; i < 3; i++){ 
    printf("%s", line[i]); 
    } 
} 

Dlaczego jest to, że po tym, jak wprowadzić 1, aby zmienić linię, drukuje oświadczenie z prośbą o to, co chcę, aby zastąpić go i automatycznie przejdzie nic następnie drukowanie ciągi z pierwszego jak pusta?

Próbowałem już bez problemu czytać linię z sscanf("%[^\n\t]s", line[0]);. Jakieś pomysły?

+0

Przypuszczam, że 'fgets' czytać EOF (koniec pliku) jako pierwsza postać strumienia. –

+0

Jestem prawie pewien, że ma to coś wspólnego z 'scanf ("% d ", & option)' przed pytaniem, czy użytkownik chciałby zamienić linię, ale nie jestem pewien, czy jest sposób, aby to naprawić. – TheBoxOkay

+2

Nie ma to bezpośredniego związku z twoim problemem, ale 'strlen (linia [0])' należy zastąpić przez '80'. Rozmiar bufora nie jest długością łańcucha, który zawiera, ale całkowitą długością bufora, który jest tutaj "80". –

Odpowiedz

10

To dlatego

scanf("%d",&option); 

pozostawia charakter \n w stdin i jest zużywana przez pierwsze wywołanie fgets(). Dlatego najlepiej jest całkowicie ominąć scanf() w C.

Można go naprawić z:

scanf("%d",&option); 
    getchar(); /* consume the newline */ 

Ale sugeruję użyciu fgets() czytać option jak również i wtedy można użyć strtol() aby przekształcić go w całkowitej.

Należy zauważyć, że to oświadczenie prawdopodobnie nie jest zgodne z zamierzeniem (co ogranicza to, co można przeczytać w line[0]).

fgets(line[0],strlen(line[0]),stdin); 

Prawdopodobnie oznaczało używać:

fgets(line[0],sizeof line[0],stdin); 

tak, że można odczytać zapisu do rzeczywistej wielkości line[0].

Proszę przeczytać wpis C Faq także: http://c-faq.com/stdio/scanfprobs.html

+3

Potwierdzam, 'scanf' jest okropny i takie problemy są powszechne. Google _scanf jest evil_ (no joke) po więcej informacji. –

+0

Dziękuję bardzo, że działało idealnie! – TheBoxOkay

2

Twoim problemem jest to, że '\n' char pozostaje w stdin i spożywane przez fgets.

którą proponujemy, aby zawsze używać fgets wejść czytać, więc

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

int main(void) 
{ 
    char line[3][80]; 
    char temp[3]; 

    strcpy(line[0],"default line 1\n"); 
    strcpy(line[1],"default line 2\n"); 
    strcpy(line[2],"default line 3\n"); 

    for(int i = 0; i < 3; i++){ 
     printf("%s", line[i]); 
    } 

    int option = 0; 
    printf("would you like to replace line 1? (1 for yes)\n"); 
    fgets(temp,sizeof(temp),stdin); 
    option = atoi(temp); 

    if(option==1){ 
     printf("what would you like to replace the line with?\n"); 
     fgets(line[0],sizeof(line[0]),stdin); 
    } 

    for(int i = 0; i < 3; i++){ 
    printf("%s", line[i]); 
    } 
} 
3

Korzystanie fgets() ogólnie wydaje się mniej podatne na błędy niż splątania z scanf(), ale jeśli użytkownik wprowadzi ciąg znaków, który jest tak długo, jak lub dłuższy niż maksymalna liczba znaków, wszelkie dodatkowe znaki do linii nowej włącznie włącznie pozostają w strumieniu wejściowym. Z tego powodu zazwyczaj piszę własną wersję gets(), aby uzyskać ciągi wejściowe od użytkownika, a jeśli chcę mieć numeryczne wejście, używam strtol(). Oto przykład takiej funkcji:

char * s_gets(char *st, int n) 
{ 
    char *ret; 
    int ch; 

    ret = fgets(st, n, stdin); 
    if (ret) { 
     while (*st != '\n' && *st != '\0') 
      ++st; 
     if (*st) 
      *st = '\0'; 
     else { 
      while ((ch = getchar()) != '\n' && ch != EOF) 
       continue;   // discard extra characters 
     } 
    } 
    return ret; 
} 

zastosowaniu do problemu OPS, mogę zrobić coś takiego:

#include <stdlib.h>    // for strtol() 

... 

char buf[80]; 
int option = 0; 

printf("would you like to replace line 1? (1 for yes)\n"); 
s_gets(buf, sizeof(buf)); 
option = strtol(buf, NULL, 10); 

if(option==1){ 
    printf("what would you like to replace the line with?\n"); 
    s_gets(line[0],sizeof(line[0])); 
}