# [c] scanf() wird übersprungen(c-Anfänger)



## heat (11. Dezember 2010)

Hallo Zusammen,

mein Programm soll einfach nur bei einer eingegebenen Zeichenkette einen frei wählbaren Buchstaben durch einen anderen ersetzen.

Den alten Buchstaben kann ich ganz einfach auswählen, aber der Neue wird irgendwie übersprungen. Wäre nett wenn ihr mir helfen könntet. 
Hier der Code


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

#define MAX_LENGTH 80

void tausch(char *, char, char);


int main()
{
    char s[MAX_LENGTH], alt, neu; 
    
    printf("Geben Sie eine Zeichenkette ein: ");
    gets(s);
    printf("\nGeben Sie an welcher Buchstabe ausgetauscht werden soll: ");
    scanf("%c", &alt);
    printf("Geben Sie nun an, mit welchem er getauscht werden soll: ");
	scanf("%c", &neu);   // <-- Hier wird scanf() ausgelassen
	printf("\n\n\n");
	tausch(s, alt, neu);
	

    getchar();
}


void tausch(char *s, char alt, char neu)
{
     int i;
     
     for(i=0; i<=strlen(s); i++)    
     {
              if (s[i] == alt)
              {
                       s[i] = neu;
              }
     }
     printf("%s", s);
}
```


----------



## sheel (11. Dezember 2010)

Willkommen bei tutorials.de 

scnaf hat leider manchmal solche Probleme...

Wenn du sowieso nur einen Buchstaben einlesen willst, wäre es am einfachsten, statt scnaf getchar zu nehmen.


```
alt=getchar();
```

Und das gleiche mit neu.

Gruß


----------



## heat (11. Dezember 2010)

Hi,

danke für deine schnelle Antwort. Ich habe es auch gleich mal geändert aber leider habe ich immer noch den selben Fehler.


----------



## sheel (11. Dezember 2010)

Tatsächlich, getchar auch.

Mit fgets funktionierts aber, habs getestet.
Du solltest auch bei s fgets verwenden, um Überläufe zu vermeiden (wenn der Benutzer mehr als 80 Buchstaben einibt, gibts bei dir sonst ein Problem).


```
int main()
{
    char s[MAX_LENGTH], alt[3], neu[3]; 
    
    printf("Geben Sie eine Zeichenkette ein: ");
    fgets(s,MAX_LENGTH,stdin);
    printf("\nGeben Sie an welcher Buchstabe ausgetauscht werden soll: ");
    fgets(alt,3,stdin);
    printf("Geben Sie nun an, mit welchem er getauscht werden soll: ");
    fgets(neu,3,stdin);
    printf("\n\n\n");
    tausch(s, alt[0], neu[0]);
    
 
    getchar();
}
```

Den Rest (die includes und tausch) gleich wie am Anfang

Gruß


----------



## heat (11. Dezember 2010)

Danke dir, jetzt klappts wie gewollt 

Eine Frage stellt sich mir aber noch zur Funktion fgets();. Ich verstehe noch nicht wieso du als Länge 3 nimmst. Hat es etwas mit Newline zu tun?



> The prototype of the function is as follows:
> char* fgets(char *string, int length, FILE * stream);
> 
> The length argument includes space needed for the null character which will be appended to the end of the string. As a result, to read N characters, the length specification must be specified as N+1.
> ...



Wenn ich danach gehe hätte ich 1 Zeichen und die '\0' sprich eine Länge von 2. Habe das auch mal ausprobiert und ich bekomme den gleichen Fehler wie bei scanf() von vorhin^^. 

Gruß


----------



## Onkel Schuppig (11. Dezember 2010)

Hallo,
fgets nimmt eine komplette Zeile inklusive newline in die Zeichenkette rein. Bei Microsoft ist das Zeilenende sogar 2 Zeichen lang: carriage return + line feed. Aber fgets() stoppt das Einlesen beim CR und hängt eine 0 hinten an. Deshalb braucht man für einen Buchstaben schon 3 Zeichen PLatz.


----------



## Matthias Reitinger (11. Dezember 2010)

heat hat gesagt.:


> Wenn ich danach gehe hätte ich 1 Zeichen und die '\0' sprich eine Länge von 2. Habe das auch mal ausprobiert und ich bekomme den gleichen Fehler wie bei scanf() von vorhin^^.


Das liegt daran, dass fgets den Rest der Zeile im Eingabestrom belässt, falls vorher schon die gegebene Anzahl an Zeichen eingelesen wurde. Wenn du hier 2 verwendest, passiert Folgendes:


Benutzer gibt z.B. a ein und drückt Return.
Im Eingabestrom befinden sich jetzt die Zeichen "a\n" (das \n ist der Zeilenumbruch).
fgets(alt,2,stdin) liest das a ein, bemerkt dass es wegen der Nullterminierung nicht mehr Zeichen einlesen kann und schreibt "a\0" in alt. Im Eingabestrom verbleibt "\n".
fgets(neu,2,stdin) liest das \n ein und erkennt es als Zeilenende. Es schreibt "\n\0" in neu.

Aber auch mit 3 bekommst du dasselbe Problem, wenn der Benutzer mehr als ein Zeichen eingibt. Auf der sicheren Seite bist du, wenn du nach jeder Eingabe ggf. die restliche Zeile aus dem Eingabestrom entfernst. Dazu kannst du z.B. folgende Funktion verwenden:

```
int ignore_line(FILE *f) {
  int c;
  while ((c = getc(f)) != '\n') {    
    if (c == EOF) return EOF;
  }
  return 0;
}
```
Deine main könnte dann so aussehen:

```
int main() {
  char s[MAX_LENGTH], alt, neu; 
    
  printf("Geben Sie eine Zeichenkette ein: ");
  fgets(s, MAX_LENGTH, stdin);
  if (s[strlen(s)-1] != '\n') ignore_line(stdin);
  printf("\nGeben Sie an welcher Buchstabe ausgetauscht werden soll: ");
  alt = getchar();
  ignore_line(stdin);
  printf("Geben Sie nun an, mit welchem er getauscht werden soll: ");
  neu = getchar();
  ignore_line(stdin);
  printf("\n\n\n");
  tausch(s, alt, neu);

  return 0;
}
```
Idealerweise solltest du auch noch mögliche Fehlerfälle abfangen, d.h. die Rückgabewerte von fgets, getchar und ignore_line abtesten.



Onkel Schuppig hat gesagt.:


> Bei Microsoft ist das Zeilenende sogar 2 Zeichen lang: carriage return + line feed. Aber fgets() stoppt das Einlesen beim CR und hängt eine 0 hinten an. Deshalb braucht man für einen Buchstaben schon 3 Zeichen PLatz.


Das ist nicht ganz richtig. fgets stoppt, wenn es ein LF ('\n') im Eingabestrom sieht. Und auch unter Windows bekommt man nur ein LF und kein CRLF wenn der Benutzer auf Return drückt.

Grüße,
Matthias


----------

