C - fgets - array zu kurz, rest als unsichtbares array im zweiten durchlauf verwertet.

phoolan

Grünschnabel
mein C programm stellt eine Eingabemaske zur verfügung (endlos while)
und liest mittels fgets Dateneingaben ein.

ist der eingegebene wert kürzer als das array das in aufnehmen soll, ist alles ok.
wenn allerdings der eingegebene wert, die länge des bereitgestellten arrays übertrifft.
also zb. array[10] und ich aber 12 zeichen eingebe,
dann wird im ersten durchlauf 1-10 aufgenommen
und sobald die funktion wieder bei fgets angekommen ist 10-12 automatisch ausgeführt.
(siehe bild)
eingabe: "hallo" -> funktioniert. count 1 (ein wort)
eingabe: "halloIchBinEinLangerTest" -> count 1 (ein wort), 3 auswertungen (halloIchBi, nEinLanger, Test\n)
eingabe: "hallo IchBinEinLangerTest" -> count 2 (zwei wörter), und 3 auswertungen


Frage: wie kann ich das verhindern? also dass der gesamte eingegebene string eingelesen wird (auf mehrere etappen) denn ich finde nichts wo fgets sich das merkt?! wenn es länger ist als das array dann könnte es entweder mit einem error sofort gestoppt werden, oder zumindest auf die max länge abgeschnitten werden.

vielen dank für die Hilfe.

C++:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main( int argc, char* argv[] ) {
if (argc == 1) {

char str[10];
char *ptr;
int count;
    char *array[5];
char delimiter[] = " ";

while(1){
  memset(str, 0, sizeof(str));
  count = 0;
  printf("prompt>");
  fgets(str, 10, stdin);
  ptr = strtok(str, delimiter);             // change sentence to words
  while(ptr != NULL) {
    array[count] = ptr;
    ptr = strtok(NULL, delimiter);
    count++;
    }
    if (count==1){
    printf("count = 1\n");
    }
    else {
    printf("count != 1\n");
    }
}
}
return 0;
}
 

Anhänge

  • Unbenannt15.JPG
    Unbenannt15.JPG
    65,4 KB · Aufrufe: 15
Zuletzt bearbeitet:
Hi

falls fgets die komplette Zeile eingelesen hat enthält der String auch den Zeilenwechsel als Zeichen, sonst nicht.
Code:
if(str[strlen(str)-1] == '\n') ...
Willst du den Rest einlesen, ignorieren oder einen "Zu lang"-Fehler ausgeben?
 
Zuletzt bearbeitet:
wenn der eingegebene wert zu lang ist,
dann soll ein fehler ausgegeben werden. (auch ignorieren würde schon helfen)
 
Also, dann kannst einfach nach dem fgets sowas machen:
C++:
if(str[strlen(str) - 1] != '\n')
{
    while(str[strlen(str) - 1] != '\n')
        fgets(str, 10, stdin);
    printf("Zu lang!\n");
    continue; //Schleife gleich wieder von vor beginnen
}

Sorry, bitte noch einmal lesen, hab zu schnell gepostet

Btw., das memset am Schleifenanfang ist eigentlich nicht nötig.

edit: Ausgebessert.
 
Zuletzt bearbeitet:
leider nicht, weil fgets erst am ende des gesamten eingelesenen string ein \n dransetzt. das heißt, erst nach dem 3ten durchgang in meinem beispiel.
damit kann ich \n nicht zur überprüfung heranziehen.

probiert habe ich es auch damit, dass ich an die letzte stelle des aktuellen (dem zum ersten mal eingelesenen arrays) dann einfach ein \n setzte, damit fgets aufhört:
size_t nr = strlen(array[0]) - 1;
array[nr] = '\n';

aber auch das wird erfolgreich ignoriert und der rest beharrlich eingelesen (wohin auch immer)
denn ein reset aller variablen
memset(str, 0, sizeof(str));
wird durchgeführt, aber sobald das fgets aufgerufen wird, wird der rest des eingegebenen strings einfach eingelesen.

ich benötige irgendetwas um ein erneutes einlesen von bereits geschriebenem text zu verhindern.
das prompt sollte nach der error meldung selbstverständlich wieder erscheinen und eine erneute eingabe soll möglich sein.

ich finde nur nichts um das bestehende (zu lange) fgets abzubrechen, nachdem "zu lange" erkannt wurde.

stimmt, fast genau so wie du gesagt hast, nur mit != :) danke

habe etwas gefunden:
http://www.gidnetwork.com/b-56.html

ursprünglich gab es mal fflush() zum leeren des puffers. das darf aber nicht mehr verwendet werden und funktionierte bei mir auch nicht.
was funktioniert ist von der oben genannten website ein "leerlaufen" des speichers in einer schleife die nicht ausgegeben wird.
das stoppt zwar das einlesen nicht. aber zumindest ist der output so wie es sein sollte und die weitere funktion:

code ausschnitt davon:

Code:
if (str[strlen(str)-1] != '\n'){
    str[0] = 0;
    char dummy[50];
    do {
    fgets(dummy, 50, stdin);
        strcat(str, dummy);
    } while (dummy[strlen(dummy)-1] != '\n');
  printf("to long!\n");
  }


gesamter code:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main( int argc, char* argv[] ) {
if (argc == 1) {

char str[10];
char *ptr;
int count;
char *array[5];
char delimiter[] = " ";

while(1){
  memset(str, 0, sizeof(str));
  memset(array, 0, sizeof(array));
  count = 0;
  printf("prompt>");
  fgets(str, 10, stdin);
  ptr = strtok(str, delimiter);
  while(ptr != NULL) {
    array[count] = ptr;
    ptr = strtok(NULL, delimiter);
    count++;
    }
  if (str[strlen(str)-1] != '\n'){
    str[0] = 0;
    char dummy[50];
    do {
    fgets(dummy, 50, stdin);
        strcat(str, dummy);
    } while (dummy[strlen(dummy)-1] != '\n');
  printf("to long!\n");
  }
  }
}
return 0;
}

danke für die hilfe.
 
Zuletzt bearbeitet von einem Moderator:
Zum Beitrag 1:
leider nicht, weil fgets erst am ende des gesamten eingelesenen string ein \n dransetzt. das heißt, erst nach dem 3ten durchgang in meinem beispiel.
damit kann ich \n nicht zur überprüfung heranziehen.
Ja eben deswegen kannst du doch prüfen, ob das \n schon da war oder nicht

Was dann mit der Variable weiter passiert ist fgets egal, Änderungen bewirken gar nichts.

Zum Beitrag 3:
Ups :eek:
Genau, != statt == im if :/

fflush war nie richtig, nur Microsoft hats schon immer absichtlich falsch gemacht und auch so falsch dokumentiert (MS hat leider die Angewohnheit, sehr viel anders zu machen als der Rest der Welt. C++/CLI, Internet Explorer 6 usw.usw)
 
  • while(ptr != NULL) {
  • array[count] = ptr; /* das geht schief, wenn count>4 ist */
  • ptr = strtok(NULL, delimiter);
  • count++;
  • }
  • if (str[strlen(str)-1] != '\n'){
  • str[0] = 0; /* das zerstört den String, auf den array[0] zeigt */
  • char dummy[50];
  • do {
  • fgets(dummy, 50, stdin);
  • strcat(str, dummy); /* das geht schief, wenn strlen(dummy)>9 ist */
} while (dummy[strlen(dummy)-1] != '\n');
Wer finalisiert eigentlich hier solche Threads?
Genaugenommen ist bei diesem "finalen" Stand fast alles falsch.
 
Was passiert wenn str leer ist? Dann gibts undefiniertes Verhalten.
Bei einem erfolgreichen fgets-Aufruf, also Returnwert nicht NULL, dürfte das nicht passieren.

Wer finalisiert eigentlich hier solche Threads?
Genaugenommen ist bei diesem "finalen" Stand fast alles falsch.
Weiß nicht genau, was du dir unter Finalisieren alles vorstellst,
aber diesen finalen Code hat sich wohl bisher niemand gründlich angeschaut.
uA. auch, weil der Fragesteller sagt, mit der Lösung zufrieden zu sein.
Wie du sagst sind da einige Probleme drin...
 
Zurück