Array behällt "new line" und "überspringt" Eingabe



  • Hallo zusammen

    danke das es dieses Forum gibt 🙂

    Ich habe zwei kleine Probleme, ich habe mehrere *.c files in Code::Blocks geschrieben, mit Borland compiler (so vorgegeben).

    Es soll ein simpler Taschenrechner für "komplexe" Zahlen handeln.

    Darunter einmal den Aufruf:

    #include <stdio.h>
    
    #include "my_complex.h"
    
    int main (void)
    
    {
        char operand;
        cplx_t p, q, ergebnis, eingabe_input, eingabe_1_alt;
    
        eingabe_input = eingabe();
    
        p.re = eingabe_input.re;
        eingabe_1_alt.re = eingabe_input.re;
        p.im = eingabe_input.im;
        eingabe_1_alt.im = eingabe_input.im;
    
        printf("Bitte Rechenoperation eingeben: ");
        scanf("%c", &operand);
    
        eingabe_input = eingabe();
    
        q.re = eingabe_input.re;
        q.im = eingabe_input.im;
    
        switch (operand)
        {
            case '+':
    
                ergebnis = cadd(p,q);
                break;
    
            case '-':
    
                ergebnis = csub(p,q);
                break;
    
            case '*':
    
                ergebnis = cmul(p,q);
                break;
    
            case '/':
    
                ergebnis = cdif(p,q);
                break;
    
        }
    
        ausgabe(eingabe_input, eingabe_1_alt, operand, ergebnis);
        return;
    }
    

    Und einmal die Eingabeabfrage im commando Fenster

    #include <stdio.h>
    #include <stdlib.h>
    
    #include "my_complex.h"
    
    #define MAX 16
    
    cplx_t eingabe (void)
    {
    
     int i, hilfs_var = 0, x = 0;
     cplx_t eingabe_1;
     char abfrage[16], zahl_1[12], zahl_2[12];
    
     printf("\nBitte komplexe Zahl wie folgt eingeben a.a+jb.b, maximal 15 Zeichen\n");
     fgets (abfrage, MAX, stdin);
    
     for (i=0; i<17; i++)
     {
    
         if ((abfrage[i] != 'j') && (hilfs_var == 0)) //Zuteilung der ersten Zahl ins Hilfsarray, testen ob es sich um Zahlen handelt.
         {
             if ((abfrage[i] == 46) || (abfrage[i] > 47) || (abfrage[i] < 58) || (abfrage[i] == 43) || (abfrage[i] == 45))
             {
                 zahl_1[x] = abfrage[i];
                 x++;
             }
    
             else i++;
         }
    
         if (abfrage[i] == 'j')
         {
             hilfs_var = 1;
             zahl_1[x-1] = '\0';
             x = 0;
             zahl_2[x] = abfrage[i-1];
             i++;
             x++;
         }
    
         if ((hilfs_var == 1) && (abfrage[i] != '\n')) //Zuteilen der zweiten Zahl, testen ob es sich um zahlen handelt.
         {
    
             if ((abfrage[i] == 46) || (abfrage[i] > 47) || (abfrage[i] < 58) || (abfrage[i] == 43) || (abfrage[i] == 45))
             {
                 zahl_2[x] = abfrage[i];
                 x++;
             }
    
             else i++;
         }
    
         if (abfrage[i] == '\n')
         {
             zahl_2[x] = '\0';
         }
     }
    
     eingabe_1.re = atoi (zahl_1);
     eingabe_1.im = atoi (zahl_2);
    
     return eingabe_1;
    }
    

    1. Problem:

    Wenn ich in Code:Blocks compiliere, wird die erste Zahl nicht richtig übernommen. Stattdessen ist sie immer 0.

    Mit Dev-Cpp compiliert funktioniert es einwandfrei.

    2. Problem:

    Jedes mal, wenn die Eingabefunktion "eingabe()" zum zweiten mal aufgerufen wird, bleibt in dem Array "abfrage" an erster Stelle ein "\n" weshalb nur der printf kommt, er aber direkt weiter macht mit der Zuteilung der Zahlen, also das new line als Eingabe versteht.

    Was kann ich dagegen machen?

    Danke!

    EDIT: Kurze beschreibung hinzugefügt.



  • Das Makro MAX ist bei dir sinnfrei, da du es nur bei fgets benutzt.
    Es gehört dann aber auch in die Definition von abfrage

    Ein Array mit 16 Elementen hat auch 16 Elmente. Deren Index geht von 0 bis 15 - und nicht bis 16.
    Darum nimmt man auch dort dann das Makro.

    Allerdings geht man bei Strings auch nicht durch das ganze Array, sondern nur bis zum Stringende.

    Schreibe keine Magic Numbers wie 46 oder 43 sondern gleich das Zeichen '.' oder '+'.
    Das kann jeder lesen und es geht auch bei anderen Codes als ASCII(-Ablegern)
    Hast du beim 'j' ja auch gemacht.
    (und bis auf Elektrotechniker schreibt die ganze Welt ein 'i' beim imaginären Teil)

    structs kann man komplett zuweisen
    p = eingabe_input;

    eingabe_1_alt = eingabe_input;
    

    scanf und fgets zu mischen macht Probleme.
    Lies nach dem Operand alles bis zum '\n' ein.

    atoi ist für Integer gedacht (daher das i am Ende), du erwartest doch aber Fließkommazahlen.
    Und nimm doch sscanf zum einlesen deiner Zahlen. Das kann auch alle gültigen Formate einlesen (z.B. 1E-3)



  • Hallo DirkB,

    danke erst mal für deine Antwort.

    Das mit MAX und 16 war etwas ungünstig, hab ich geändert.
    Die Magic Numbers habe ich genommen, um zu testen ob es so funktioniert,
    natürlich machen die Zeichen direkt mehr Sinn.

    Stimmt, das mit den structs ist wieder so ein Geniestreich, fällt mir jetzt auch erst auf.

    Ich hab auch schon alternativ den "operand" mit getchar() probiert.
    Also besser wie in der Eingabe das Array abarbeiten?

    Und ja, atoi habe ich vorhin auch geändert,
    ich habe diesbezüglich noch nicht so viel Erfahrung.

    EDIT: atof nimmt Code::Blocks nicht, atoi schon ....



  • Ich hab das ganze abgeändert zu

    printf("Bitte Rechenoperation eingeben: ");
    
        fgets (operand, 2, stdin);
    

    Das Problem bleibt das gleiche.

    Was mir noch aufgefallen ist, als ich den Wert im watch hatte,
    dass beim erneuten Aufruf der Funktion eingabe() der string der im Array lag gelöscht wird, das "\n" aber bleibt.

    Nach der ersten Eingabe sieht es wie folgt aus:

    abfrage = 1+i2\n\000...
    

    Nach dem erneuten Aufruf:

    abfrage = \n\000...
    


  • Grizzy schrieb:

    Ich hab das ganze abgeändert zu

    printf("Bitte Rechenoperation eingeben: ");
    
        fgets (operand, 2, stdin);
    

    Das Problem bleibt das gleiche.

    2 ist auch ein bisschen wenig Platz für den Operator, das '\n' von der Entertaste (dein Problem) und den Stringterminator '\0'.

    Ob du die gesamte Zeile gelesen hast, kannst du daran erkennen, dass das '\n' im String mit abgelegt wurde.

    Und auch wenn du das auf 3 änderst, was reicht, ist das doch etwas geizig.

    Das ist alles kein Geheimnis sondern ist in jeder Referenz/Man page nachzulesen.

    Grizzy schrieb:

    EDIT: atof nimmt Code::Blocks nicht, atoi schon ...

    DAs ist eine sehr ausagekräftige und genaue Fehlerangabe 👍

    Der Compiler macht i.A. sehr genaue Angaben, was ihm nicht gefällt oder womit er Probleme hat.
    Auch wenn du damit nichts anfangen kannst, können es Andere. Dazu braucht man aber den genauen Wortlaut der Meldungen (Copy&Paste)

    Und die richtige Funktion wäre auch strtod



  • Ich entschuldige mich für die ungenaue Angabe, du hast natürlich Recht.

    Punkt 1:

    Ich habe den Wert auf 4 erhöht, man soll ja Speicherplatz sparend arbeiten. In der gängigen Lektüre heißt es ja "Es wird bis "new Line" oder EOF eingelesen", nicht und EOF. Deshalb habe ich das nicht berücksichtigt.

    Jetzt funktioniert es wie es soll, Danke!

    Punkt 2:

    Ich bekam die Meldung

    Unresolved external '_atof' referenced from
    

    Nachdem ich das Programm nach einer Pause neu gestartet habe compiliert er anstandslos.

    Ein letztes Problem bleibt noch.

    Punkt 3:

    Der erste, eingegebene Zahlenwert wird nicht verarbeitet. Ich kann leider nicht feststellen wo das Problem genau liegt, da ich keine "watches" im Debugger nutzen kann, da Code::Blocks diesbezüglich allem Anschein nach nicht mit Borland zusammen arbeitet.

    Wenn ich die gleichen Files in Dev-Cpp öffne und dann compiliere funktioniert es, da wird die erste, eingegebene Zahl verarbeitet so wie es soll.

    EDIT:

    Wo liegt denn der Unterschied zwischen atof and strtod? Ich hatte durch meine Suche nach den entsprechenden Kommandos nur atof gefunden.



  • Grizzy schrieb:

    Ich habe den Wert auf 4 erhöht, man soll ja Speicherplatz sparend arbeiten.

    Ich würde behaupten, auf modernen Prozessoren kannst du bis 64 Bytes (Cacheline) gehen, bevor du mit ganz, ganz viel Glück überhaupt was messen kannst.

    Grizzy schrieb:

    Der erste, eingegebene Zahlenwert wird nicht verarbeitet. Ich kann leider nicht feststellen wo das Problem genau liegt, da ich keine "watches" im Debugger nutzen kann, da Code::Blocks diesbezüglich allem Anschein nach nicht mit Borland zusammen arbeitet.

    Und einfach printf für die Ausgabe zu verwenden kommt nicht in Frage?

    Grizzy schrieb:

    Wo liegt denn der Unterschied zwischen atof and strtod? Ich hatte durch meine Suche nach den entsprechenden Kommandos nur atof gefunden.

    Wo zur Hölle hast du gesucht?



  • dachschaden schrieb:

    Und einfach printf für die Ausgabe zu verwenden kommt nicht in Frage?

    Das wäre ja zu einfach 🙄

    dachschaden schrieb:

    Wo zur Hölle hast du gesucht?

    Wenn man das Kommando nicht kennt, wie genau soll man danach suchen? Ich habe nach einer Möglichkeit gesucht, strings in integer/float Zahlen umzuwandeln. Die erste Ergebnisseite war nur atoi.



  • @DirkB

    Ich habe es jetzt zu strtod umgeändert, funktioniert sehr gut und ist deutlich kürzer, Danke für deine Hilfe!
    Nichts desto trotz werde ich dann mal die Tage mit printf gucken wo genau das Problem liegt, dass Code::Blocks die erste Zahl nicht verarbeitet, Dev-Cpp schon.

    Danke euch allen die sich die Mühe gemacht haben!



  • Grizzy schrieb:

    Das wäre ja zu einfach 🙄

    Dann beschwere dich nicht.

    Grizzy schrieb:

    Wenn man das Kommando nicht kennt, wie genau soll man danach suchen?

    Grizzy schrieb:

    Wo liegt denn der Unterschied zwischen atof and strtod?

    Ich bezog mich nicht darauf, dass du strtod nicht gefunden hast, sondern dass du augenscheinlich an der falschen Stelle nach Dokumentation für strtod gesucht hast.

    "Oh, ich sehe hier strtod , das kann auch Strings in double s umwandeln, aber meine Dokumentation gibt mir keine Informationen darüber. Anstatt also mal Google zu verwenden, frage ich lieber noch mal nach, obwohl mir diese Leute auch nichts anderes sagen werden".

    Aber weißt du was? Verschissen hast du so oder so - c string to float kann man auch googlen, beschreibt exakt deine Fragestellung, und zeigt dir alles, was du brauchst.



  • dachschaden schrieb:

    Dann beschwere dich nicht.

    Ich habe mich lediglich über mich selbst geärgert.

    dachschaden schrieb:

    Aber weißt du was? Verschissen hast du so oder so - c string to float kann man auch googlen, beschreibt exakt deine Fragestellung, und zeigt dir alles, was du brauchst.

    Genau danach habe ich bei google gesucht:

    string in zahl umwandeln c
    

    Und die ersten Ergebnisse sind alle atoi, und wenn man die Alternativen nicht kennt, kann man auch nicht danach suchen, eigentlich selbstverständlich...



  • @DirkB

    Ich habe auch den Fehler gefunden, warum der Wert abhanden gekommen ist. Da die Arrays für die Zahlen nur 12 Stellen haben und er bei der zweiten Zahl bei der Zuweisung über diese 12 Stellen hinaus gekommen ist, hat er die erste überschrieben. Wenn die Zahlen ausreichen viele Stellen haben, passiert dies nicht.



  • Grizzy schrieb:

    Genau danach habe ich bei google gesucht

    Auf Deutsch. So was machst du am Besten immer in Englisch.



  • Grizzy schrieb:

    Ich entschuldige mich für die ungenaue Angabe, du hast natürlich Recht.

    Punkt 1:

    Ich habe den Wert auf 4 erhöht, man soll ja Speicherplatz sparend arbeiten. In der gängigen Lektüre heißt es ja "Es wird bis "new Line" oder EOF eingelesen", nicht und EOF. Deshalb habe ich das nicht berücksichtigt.

    Jetzt funktioniert es wie es soll, Danke!

    New Line ist das '\n'
    EOF steht für End of File. Das ist in diesem Fall kein Zeichen, sondern ein Zustand.
    Da kommen keine Zeichen mehr, also kann auch kein weiteres abgespeichert werden.
    '\0' kennzeichnet das Stringende in C. Wenn das fehlt, kannst du keine Stringfunktionen aus der Standardbibliothek benutzen.

    Diesen Speichergeiz kannst du auf Mikrocontrollern ausleben, aber nicht unbedingt auf einem modernen PC, wo auch noch ein Mensch die Eingabe macht.



  • Wieder etwas dazu gelernt, jetzt funktioniert ja alles wie es soll. Danke nochmal!


Anmelden zum Antworten