C - Mittelwert berechnen



  • Hallo,

    ich beschäftige mich zur Zeit mit der C Programmierung und möchte den Mittelwert von Dezimalzahlen berechnen. Leider habe ich Probleme beim abfangen, ob die Eingabe wirklich eine Zahl war. Es klappt zwar momentan, jedoch wird das Ergebnis verfälscht weil die erste Eingabe übersprungen wird. Was (wie ich glaube) an der Überprüfung liegt, ob eine Zahl eingegeben wurde.

    Es wäre super, wenn mir jemand helfen könnte! Danke schonmal 🙂

    #include <stdio.h>
    #include <float.h>
    #include <math.h>
    
    int main(){
    
    	float Eingabe = 0.0;
    	float i = 0.0;
    	float Mittelwert = 0.0;
    
    	while((scanf("%f", &Eingabe) != EOF)){
    
    	if(!scanf("%f", &Eingabe)){
    		printf("Fehler bei der Eingabe");
    		return 1;
    	}
    
    	Mittelwert += Eingabe;
    	i++;
    
    	}
    
    	Mittelwert = Mittelwert / i;
    
    	printf("Lösung: %f", Mittelwert);
    
    	return 0;
    
    }
    


  • Klar, Du rufst 2x scanf auf und wirst das erste Ergebnis weg!



  • Im Prinzip brauchst du nur die redundante if Bedingung entfernen, dann läufts im Grunde schon mal.

    #include <stdio.h> 
    #include <float.h> 
    #include <math.h> 
    
    int main() { 
      float Eingabe = 0.0; 
      float i = 0.0; 
      float Mittelwert = 0.0; 
    
      while ((scanf("%f", &Eingabe) != EOF)) { 
        Mittelwert += Eingabe; 
        i++;
      }
    
      Mittelwert = Mittelwert / i; 
      printf("Lösung: %f", Mittelwert); 
    
      return 0; 
    }
    

    Es empfiehlt sich auch, den Rückgabewert von scanf nicht direkt mit EOF zu vergleichen, weil laut der Dokumentation die scanf Funktion die Anzahl der erfolgreich gelesenen Werte zurück gibt. Heißt ein Vergleich scanf(...) > 0 wäre sinvoller.
    Wenn du genau wissen willst, ob scanf korrekt eingelesen hat, oder ob das Ende der Eingabe erreicht wurde, müsstest du den Rückgabewert in einer Variable zwischenspeichern und dann eben schauen ob der Wert == 0 oder == EOF ist.



  • Danke für eure Hilfe bis hierhin!

    Ja genau, dass es funktioniert, wenn ich die if-Anweisung entferne wusste ich, jedoch möchte ich ja wissen, wie ich überprüfe ob eine Zahl eingegeben wurde.

    Du sagst, ich müsste den Wert von scanf zwischenspeichern und überprüfen ob er == 0 ist, heißt das, dass wenn man einen Buchstaben eingibt, die Eingabe dann == 0 ist?

    Danke!



  • leroxxx schrieb:

    Du sagst, ich müsste den Wert von scanf zwischenspeichern und überprüfen ob er == 0 ist, heißt das, dass wenn man einen Buchstaben eingibt, die Eingabe dann == 0 ist?

    Genau. Zumindest in deinem Fall.

    scanf sieht anhand von deinem "%f", dass du einen float lesen willst.
    Ist die Eingabe korrekt, gibt dir scanf eine 1 zurück, was heißt, dass ein Element korrekt gelesen werden konnte.

    Würdest du "%d %f" an scanf als Formatparameter übergeben, würde scanf versuchen zuerst einen int (d für int) und gleich dannach einen float zu lesen.
    Wäre zum Beispiel das Lesen von dem int erfolgreich, aber nicht vom float, gibt dir scanf wieder eine 1 zurück, weil genau ein Element korrekt gelesen wurde.
    Kann scanf den int und den float beide lesen, gibt es dir eine 2 zurück, weil beide Elemente richtig gelesen wurden.

    Wenn keine einziges Element gelesen werden konnte, bekommste ebene eine 0.
    Ein Rückgabewert -1 bedeutet, dass scanf keine Daten mehr zum lesen bekommen hat, oder etwas anderes schiefgelaufen ist. Ein solcher Grund könnte sein, dass einfach das Ende der Eingabe erreicht wurde. EOF.
    EOF selbst ist in Wirklichkeit nichts anderes als der Integer -1.



  • Du musst dabei aber bedenken, dass ein falsches Zeichen weiterhin im Eingabestrom steht.
    scanf stellt dieses Zeichen wieder zurück.

    Beim nächsten lesen bekommst du es wieder.
    Du musst also dafür sorgen, dass dieses Zeichen dann "verschwindet"



  • Hallo leroxxx!

    Ist eine gute Idee, die Eingabe auf Richtigkeit zu prüfen!

    Warum liest du nicht die Zahl als String ein und Prüfst diese, ob nur
    auf erlaubte Zeichen?
    Falls ja, dann Umwandlung, falls nein, Fehlermeldung.

    Beispiel-Funktion:

    //Falls nur Zeichen aus dem String "soll" vorkommen ist Rückgabewert = 0, sonst 1
    int pruefestring(char wort[], char soll[])
      {
       int slei, sleib, lgeist, lgesoll, rewer = 0;
       lgeist  = strlen(wort);
       lgesoll = strlen(soll);
    
      for (slei = 0; slei < lgeist; slei++)
        {
         if (rewer == lgesoll) break;
          for (sleib = 0; sleib < lgesoll; sleib++)
         {
          if (wort[slei] != soll[sleib])
           {
            ++rewer;
           }
           else
            {
             rewer = 0;
             break;
            }
         }
       }
    
       if (rewer) rewer = 1;
       return rewer;
      }
    

    Falls zum Beispiel statt ein Punkt ein Komma verwendet wurde, kann dann
    der String automatisch korrigiert werden, zum Beispiel mit:

    void kommazupunkt(char zahl[])
    {
     int wolen = 0, slei = 0;
     wolen = strlen(zahl);
    
     for (slei = 0; slei < wolen; slei++)
      if (zahl[slei] == ',') zahl[slei] = '.';
    
    }
    

    Benutzt werden könnte das zum Beispiel wie :

    #include <iostream>
    using namespace std;
    #include <string.h>
    #include <stdlib.h>
    #include <math.h>
    
    #include <sstream> //Für _atoi und Co
    
    int _atoi(std::string zawo)
    {
     int rewer = 0;
     std::istringstream b(zawo);
     b >> rewer;
     return rewer;
    }
    
    std::string _itoa(int number)
    {
     std::ostringstream buff;
     buff << number;
     return buff.str();
    }
    
    long double _atold(std::string zawo)
    {
     long double rewer = 0;
     std::istringstream b(zawo);
     b >> rewer;
     return rewer;
    }
    
    void kommazupunkt(char zahl[])
    {
     int wolen = 0, slei = 0;
     wolen = strlen(zahl);
    
     for (slei = 0; slei < wolen; slei++)
      if (zahl[slei] == ',') zahl[slei] = '.';
    
    }
    
    void StringToChar(std::string wort, char satz[])
    {
    int slei, wolen;
    wolen = wort.length();
    
    for (slei = 0; slei < wolen; slei++)
     {
     satz[slei] = wort[slei];
     satz[slei +1] = '\0';
     }
    
    }
    
    double _atod(std::string zawo)
    {
     double rewer = 0;
     std::istringstream b(zawo);
     b >> rewer;
     return rewer;
    }
    //Falls nur Zeichen aus dem String "soll" vorkommen ist Rückgabewert = 0, sonst 1
    int pruefestring(char wort[], char soll[])
      {
       int slei, sleib, lgeist, lgesoll, rewer = 0;
       lgeist  = strlen(wort);
       lgesoll = strlen(soll);
    
      for (slei = 0; slei < lgeist; slei++)
        {
         if (rewer == lgesoll) break;
          for (sleib = 0; sleib < lgesoll; sleib++)
         {
          if (wort[slei] != soll[sleib])
           {
            ++rewer;
           }
           else
            {
             rewer = 0;
             break;
            }
         }
       }
    
       if (rewer) rewer = 1;
       return rewer;
      }
    
    int main()
    {
        int wohin = 8, myint, x = 245, basis = 10, wolen, test;
        string zahl;
        char zahlwort[300], solltest[15] = {"0.123456789"};
        long double kommazahl;
    
        zahl = "10100";
    
        do
        switch(wohin)
        {
         default:
           cout << endl << "Zahlenwandler" << endl;
           cout << "Basis.......: " << basis << endl;
           cout << "Stringzahl..: " << zahl << endl;
           cout << "Dezimal.....: " << x << endl;
           cout << "Programm beenden.........1" << endl;
           cout << "Zahl als String eingeben.2" << endl;
           cout << "Basis eingeben...........3" << endl;
           cout << "String zu Dezimalzahl....4" << endl;
           cout << "Dezimalzahl eingeben.....5" << endl;
           cout << "Dezimal zu String........6" << endl;
           cout << "String zu double.........7" << endl;
           cout << endl << "Ihre Wahl: " << endl;
           cin >> wohin;
          break;
    
        case 1:
           return 0;
          break;
    
        case 2:
           cout << "Zahl als String eingeben" << endl;
           cout << "Bitte Integer-Zahl eingeben: ";
           cin >> zahl;
           StringToChar(zahl, zahlwort);
           cout << "Eingabe war................: " << zahl << endl;
           test = pruefestring(zahlwort, solltest);
           if (test) cout << "Zeichenfolge enthält andere Zeichen als " << solltest << endl;
           wohin = 8;
          break;
    
        case 3:
           cout << "Bitte Basis der umzuwandelnden Zahl eingeben: ";
           cin >> basis;
           wohin = 8;
          break;
    
        case 4:
           cout << endl << "Basis der Stringzahl.: " << basis << endl;
           cout << "Zahl als String......: " << zahl << endl;
           /* alt war */
           //myint = strtol(zahl, &stop, basis);
           //cout << "Stop bei Zeichenfolge: " << stop << endl;
           myint = _atoi(zahl);
           cout << "Als Dezimalzahl......: " << myint << endl;
           wohin = 8;
          break;
    
        case 5:
           cout << "Bitte Ganze Dezimalzahl eingeben: ";
           cin >> x;
           cout << "Zahl war: " << x << endl;
           wohin = 8;
          break;
    
        case 6:
           cout << endl << "Dezimal zu String umwandeln" << endl;
           cout << "Basis der Dezimalzahl...: " << basis << endl;
           cout << "Dezimalzahl..........: " << x << endl;
           zahl[0] = '\0';
           zahl = _itoa(x);
           cout << "Als String...........: " << zahl << endl;
           wohin = 8;
          break;
    
        case 7:
           cout << endl << "String zu double umwandeln" << endl;
           wolen =zahl.length();
           StringToChar(zahl, zahlwort);  //= zahl.c_str();
           kommazupunkt(zahlwort);
           cout << endl << "Als String..............: " << zahlwort << " mit " << wolen << " Zeichen Länge" << endl;
           kommazahl = _atold(zahlwort);
           cout.precision(20);
           cout << "long double-Zahl.. ......: " << kommazahl << endl;
           //cout << "Stopzeichenfolge: " << stop << endl;
           wohin = 8;
          break;
       }
        while (wohin != 1);
    
      return 0;
    }
    

    Der Code ist zwar nicht perfekt, aber ich hoffe du weist, was ich meine.
    Nach dem eine fehlerhafte Eingabe festgestellt wurde, kannst du ja die Eingabe
    zum Beispiel bis zu 5 Versuche wiederholen, um bei erneuter fehlerhafter
    Eingabe das Programm oder die Prozedur abzubrechen.

    Also aufrufen könnte man das ganze mit

    int test;
    
    test = pruefestring(zahlwort, solltest);
     if (test) cout << "Zeichenfolge enthält andere Zeichen als " << solltest << endl;
    

    Den Eingabepuffer kann man mit clpuf() aus folgender Include-Datei Leeren:

    ifndef GETCH_H_INCLUDED
    #define GETCH_H_INCLUDED
    
    #include <stdio.h>
    #include <termios.h>
    #include <unistd.h>
    
    int getch(){
        struct termios oldt, newt;
        int ch;
        tcgetattr( STDIN_FILENO, &oldt );
        newt = oldt;
        newt.c_lflag &= ~( ICANON | ECHO );
        tcsetattr( STDIN_FILENO, TCSANOW, &newt );
        ch = getchar();
        tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
        return ch;
    }
    
    void clpuf(void)
     {
     while (getc(stdin) != '\n')
        ;
     }
    
    #endif // GETCH_H_INCLUDED
    

    Hoffe geholfen zu haben


  • Mod

    Schrecklicher C/C++-Mischmasch. Schreckliche Algorithmen zur Verarbeitung von Zeichenketten. So bitte nicht machen!



  • Test auf erlaubte Zeichen reicht nicht; damit läßt man immer noch beliebig lange Ziffernketten durch. Beim ersten lauert noch eine div by zero. Und ++ bei floats sieht auch komisch aus.


Log in to reply