einlesen von unterschiedlich langen Zeichenketten



  • Hallo zusammen,

    euer Forum hat mir schon des öfteren geholfen, doch jetzt hab ich auch ein ungelöstes Problem...
    Es geht um die Programmierung einer Enigma.

    Und zwar hab ich in einem struct ein char array mit vor definiereter Länge.
    Dieses Array will ich mit Buchstaben aus einer Eingabe füllen. Jeder einzelne Buchstabe wird dann codiert. Doch ich hab hier Probleme mit den Bedingungen.

    struct Maschine
    {                                                                                   //Enigma wird als struct definiert
        char eingabe[500];
        char ausgabe[500];
        char Walzen[5][27];
       // char Reflektor[][];
    };
    
    printf("Nun können Sie den zu codierenden Text eingeben");
        scanf("%5c", &Enigma.eingabe);
    
    int zaehler = 5;
    
                for (int i = 0; i <= zaehler; i++)                                                 // Schleifen Bedingung ?!?!?!?!
                {
    
                    char b = Walze1(Enigma.eingabe[i], Enigma, eingabe[0], PosW);
                    //printf("%c", b);
                    char erg1 = Walze2(b, Enigma, eingabe[1], PosW);
                    //printf("%c", erg1);
                    char erg2 = Walze3(erg1, Enigma, eingabe[2], PosW);
                    printf("%c\n", erg2);
                    erg2 = Enigma.ausgabe[i];
    
                }
    

    Der Code an sich funktioniert soweit.
    Nur hab ich jetzt das Problem das ich bei scanf die 5 Stellen einlesen kann, wenn bei int zaehler auch 5 steht ist das gar kein Problem, doch wird der zu codierende Text immer unterschiedlich lang sein. Wenn ich bei zaehler = 500 nehme aber nur 10 bei scanf einlese wird aus den unbeschriebenen Zellen nur Mist angezeigt.

    Wenn ich es anderstrum mach, also bei scanf("%500c",a) dann verlangt es bei mir immer genau 500 Elemente obwohl ich beispielsweiße nur 100 brauche... 😞

    Gibt es irgendeinen anderen Lösungsweg?

    Vielen vielen Dank! 🙂



  • Indem du keine Arrays vordefinierter Größe,
    sondern realloc verwendest und dann in jeden Schleifendurchlauf um ein char vergrößerst.



  • Die Lösung ist %s. scanf gibst du dann einen zeiger auf den Anfang eines char-arrays, welches dann mit den zeichen befüllt wird. Am ende wird noch eine null, nicht das zeichen, sondern der wert null. eingefügt damit du weißt, wie lang die zeichenkette ist.



  • Der Formatspecifier zum einlesen von Zeichenketten ist %s.
    Der fügt auch automatisch den Terminator ('\0') an, den du als Endekennung nehmen kannst.

    Auch ist beim scanf der Adressoperator bei Arrays nicht nötig.

    Zudem ist das <= in der for-Schleife falsch. Da du bei 0 anfängst, hast du einen Durchlauf zuviel.



  • Vielen Dank für die schnellen Antworten!

    Habe den Code umgeschrieben,

    printf("Nun können Sie den zu codierenden Text eingeben");
        scanf("%s", Enigma.eingabe);
    
    for (int i = 0; Enigma.eingabe[i] != 0 ; i++)                                                
                {
    
                    char b = Walze1(Enigma.eingabe[i], Enigma, eingabe[0], PosW);
                    //printf("%c", b);
                    char erg1 = Walze2(b, Enigma, eingabe[1], PosW);
                    //printf("%c", erg1);
                    char erg2 = Walze3(erg1, Enigma, eingabe[2], PosW);
                    printf("%c\n", erg2);
                    erg2 = Enigma.ausgabe[i];
    
                }
    

    Jetzt sollte doch die letzte Stelle der Zeichenkette eine 0 sein. Doch die Abbruchbedingung funktioniert nicht.
    Beim debuggen springt er nichtmal in die For-Schleife hinein 😮



  • Wie DirkB gesagt hat: der & operator beim scanf ist fehl am Platz.



  • Bitmapper schrieb:

    Wie DirkB gesagt hat: der & operator beim scanf ist fehl am Platz.

    Hab ihn rausgemacht, nur die falsche Version hier rein kopiert...
    Es funktioniert trotzdem noch nicht.

    Beim einlesen des Strings mit %s, wird dort am Ende ein Element mit dem Wert 0 also Hex 0x00, oder NULL hinterelegt, welches ich als Abbruchkriterium verwenden könnte?



  • Sollte so funktionieren.



  • mawame07 schrieb:

    Bitmapper schrieb:

    Wie DirkB gesagt hat: der & operator beim scanf ist fehl am Platz.

    Hab ihn rausgemacht, nur die falsche Version hier rein kopiert...
    Es funktioniert trotzdem noch nicht.

    Hast du noch etwas am Code geändert und vergessen?

    mawame07 schrieb:

    Beim einlesen des Strings mit %s, wird dort am Ende ein Element mit dem Wert 0 also Hex 0x00, oder NULL hinterelegt, welches ich als Abbruchkriterium verwenden könnte?

    0 oder '\0' (hat beides den Wert Null).
    NULL hat eine andere Bedeutung.

    Das ist dann ein C-String und wichtige Grundlage in C.
    Damit arbeitet die C-Standardlibrary und (fast) alle anderen, die in C Strings benutzen.

    Gib doch in der Schleife erstmal die Eingabe aus. Dann siehst du ob es klappt.

    printf("%c", Enigma.eingabe[i]);
    


  • Vielen Dank!

    Ich habe nun die Funktion etwas verändert. Sie bekommt jetzt die Enigma als Rückgabe, jetzt wird das 0 in der Zeichenkette auch erkannt und richtig ausgegeben bzw. das Abbruchkriterium erfüllt sich.

    Maschine einlesen(Maschine Enigma)                                                               //Eingabe des zu codierenden Textes
    {
        printf("Nun können Sie den zu codierenden Text eingeben");
        scanf("%s", Enigma.eingabe);
    
        return Enigma;
    }
    

    und der Code für die Verschlüsselung

    for (int i = 0; Enigma.eingabe[i] != 0 ; i++)                                                 // Schleifen Bedingung ?!?!?!?!
                {
                    //printf("%c", Enigma.eingabe[i]);
                    char b = Walze1(Enigma.eingabe[i], Enigma, eingabe[0], PosW);
                   // printf("%c", b);
                    char erg1 = Walze2(b, Enigma, eingabe[1], PosW);
                   // printf("%c", erg1);
                    char erg2 = Walze3(erg1, Enigma, eingabe[2], PosW);
                    printf("%c\n", erg2);
                    erg2 = Enigma.ausgabe[i];
    
                }
    

    Das Funktioniert jetzt soweit ganz gut, mir sind im Verschlüsselungsteil aber noch ein paar kleine Ungereihmtheiten aufgefallen, die ich aber noch beheben kann denk ich 🙂



  • Wie rufst du einlesen() auf? Wahrscheinlich genau so ergebnis=einlesen()? Dann ist das "Maschine Enigma" falsch, die Funktion erwartet keine Parameter also muss da Machine einlesen(void) stehen. Der Compiler müsste eigentlich meckern ("unused variable") aber wahrscheinlich sind die Warnungen abgeschaltet (nicht gut).



  • dönerknödel schrieb:

    Wie rufst du einlesen() auf? Wahrscheinlich genau so ergebnis=einlesen()? Dann ist das "Maschine Enigma" falsch, die Funktion erwartet keine Parameter also muss da Machine einlesen(void) stehen. Der Compiler müsste eigentlich meckern ("unused variable") aber wahrscheinlich sind die Warnungen abgeschaltet (nicht gut).

    nicht ganz, ich übergeb der Funktion mein struct Maschine, in die sie dann die Buchstaben einließt, die dann von der Funktion zurückgegeben werden.

    Es kommt keine Fehlermeldung oder Warnung:
    ========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
    (Visual Studio 2015)

    Aber Ich weiß, man hätte das auch mit einer globalen Variable und wie du sagst einlesen(void) machen können.



  • Also sowas wie var=einlesen(var)? Zugegeben, das funktioniert auch, ist aber irgendwie unelegant finde ich. Du übergibst eine Kopie in die dann geschrieben wird und welche zurückgegeben wird. Aber immer noch besser als globale Variablen.

    Ich würde einen Pointer nehmen:

    #include <stdio.h>
    
    typedef struct 
    {                                                                                   //Enigma wird als struct definiert
        char eingabe[500];
        char ausgabe[500];
        char Walzen[5][27];
       // char Reflektor[][];
    }Maschine;
    
    void einlesen(Maschine *Enigma)                                                               //Eingabe des zu codierenden Textes
    {
        printf("Nun können Sie den zu codierenden Text eingeben");
        scanf("%s", Enigma->eingabe);
    }
    
    int main(void)
    {
    	Maschine m;
    
    	einlesen(&m);
    
    	return 0;
    }
    


  • mawame07 schrieb:

    , ich übergeb der Funktion mein struct Maschine, in die sie dann die Buchstaben einließt, die dann von der Funktion zurückgegeben werden.

    Die Variable Enigma ist in der Funktion eine lokale Variable.
    Änderungen daran haben keine Auswirkung auf die Rufende Funktion.

    Da du keine Information über Enigma in die Funktion gibst, ist sie als PArameter überflüssig.
    Es ist somit kein Unterschied zu

    Maschine einlesen(void)                                                               //Eingabe des zu codierenden Textes
    {   Maschine Enigma;
    
        printf("Nun können Sie den zu codierenden Text eingeben");
        scanf("%s", Enigma.eingabe);
    
        return Enigma;
    }
    

    Da dein struct mit 1000 Byte relativ Groß ist, finde ich die Zeigervariante von dönerknödel besser.

    Allerdings ist der Name der Funktion zu Allgemein.



  • @DirkB
    Was du schreibst ist natürlich richtig (was anderes erwarte ich bei dir auch nicht), aber in diesem Fall haben Änderungen in der Funktion einlesen() doch eine Wirkung weil die Funktion so weit ich verstehe so aufgerufen wird:

    Machine m;
    m.irgendwas=42; //soll heissen m wird benutzt/gefüllt
    m=einlesen(m); //wodurch Änderungen in der Funktion übernommen werden.



  • Wobei, wenn m bei Aufruf von einlesen() noch "leer" (uninitialisiert) ist gibt es in der Tat keinen Unterschied wie du sagst. Sorry, zu schnell.


Anmelden zum Antworten