Importer:Error:WasEmpty



  • Hallo,
    ich habe folgendes Problem:

    Ich habe das Grundgerüst einer Funktion gegeben. Die Funktion soll (unbekannte) Werte einlesen und davon den Mittelwert berechnen und zurückliefern. Mein Problem dabei ist, dass die Funktion nur einen Parameter enthält und ich nicht weiß wie ich damit das Array befüllen soll.

    Hier das Grundgerüst: (hier darf nichts verändert werden!)

    double funktion(double wert)
    {
    double mittelwert=.0;
    #define Fenster 15

    return mittelwert;
    }

    Meine Lösung bis jetzt:

    double funktion(double wert)
    {
    double mittelwert=.0;
    #define Fenster 15
    int i;
    double x[Fenster];
    double summe=.0;

    for(i=wert;i<Fenster;i++){

    summe += x[i];
    }

    mittelwert = summe/Fenster;
    return mittelwert;
    }

    Ja wäre nett wenn mir jemand zumindest einen Hinweis geben könnte, wie ich das Problem hier lösen kann.

    Gruß



  • Ganz sicher, dass es nicht double funktion(double *wert) ist?



  • Um sinnvoll zu sein muss die Angabe genauer sein.
    Entweder du unterschlägst uns hier jetzt einiges, oder die Angabe ist Topfen.

    Eine Möglichkeit wäre z.B. mit statischen Variablen zu arbeiten. Ich hoffe dass das nicht gemeint ist, aber bei dem was ich gelernt habe von Lehrern/Professoren zu erwarten würde es mich auch nicht wundern.



  • Nein ich habe nichts unterschlagen, wert ist kein Zeiger und auch sonst stimmt alles, habs eben nochmal überprüft.



  • Also in der Angabe steht dass die Funktion Werte einlesen soll, die Funktions-Signatur die vorgegeben ist enthält aber einen Parameter der "wert" heisst?
    Das beisst sich doch. Sollen die Werte jetzt eingelesen werden oder werden sie übergeben?

    Davon abgesehen glaub' ich dir nicht dass du die Angabe hier vollständig wiedergegeben hast. So schlecht kann keine Angabe sein.



  • hustbaer schrieb:

    So schlecht kann keine Angabe sein.

    Ich fürchte schon, wenn die ANgabe von demselben C++-Analphabeten stammt, der das hier verzapft hat:

    #define Fenster 15
    int i;
    double x[Fenster];
    


  • Also hier noch ein paar Zusatzinfos die ich auf Nachfrage erhalten habe:

    die Signatur muss in jedem Fall eingehalten werden. Die Funktion bekommt regelmäßig fortlaufend Werte, zum Beispiel alle 10 ms Messwerte welche von einem Timer-getriggerten ADC digitalisiert wurden. Die Aufgabe besteht darin Unregelmäßigkeiten/Störungen/Sprünge die in dem Wertestrom vorkommen können zu filtert bzw. glätten. Die Anzahl der Messwerte, wie oft die kommen, wo und wie diese abgelegt sind und was damit gemacht wird soll/muss dem Entwickler der Funktion egal sein (Geheimnisprinzip/Modularisierung). Der "Anwender" der Funktion hat die gegebene Schnittstelle (Signatur) und stopft nacheinander alle seine Werte da rein und erhält für jeden Wert den er übergibt einen gefilterten Wert zurück. Wie die Funktion das macht ist ihm eigentlich egal (dito. Geheimnisprinzip). Der Entwickler der Funktion legt die Fenstergröße (Anzahl der Werte über die der Mittelwert gebildet wird) fest und muss dafür sorgen, dass er sich nur die Werte welche im Fenster liegen "merkt" um den Mittelwert zu berechnen.

    Hoffe das hilft bei der Lösung.



  • Jetzt, wo die Aufgabe klar ist, verstehe ich nicht mehr so ganz, was dir daran noch unklar ist. Du brauchst ein statisches Array, in das du nach und nach die Werte reinschreibst. Wenn das Array voll ist, musst du dir was überlegen ... Stichwort Ringpuffer. Und dann halt immer den Mittelwert ausrechnen und zurückgeben.



  • c++123 schrieb:

    double funktion(double wert)
    {
      double mittelwert=.0;
    #define Fenster 15
      int i;
      double x[Fenster];
      double summe=.0;
    
      for(i=wert;i<Fenster;i++){
    
        summe += x[i];
      }
    
      mittelwert = summe/Fenster;
      return mittelwert;
    }
    

    Okay: um Missverstaendnissen vorzubeugen: es geht um C++, nicht C?

    Dann sieht das ja schon gar nicht so schlecht aus. Geht aber hier und da ein bisschen verquer - wie du sicherlich schon bemerkt hast.

    Sagen wir, Du hast folgende Situation:

    double values[10] = { 0., 1., 2., 3., 4., 5., 6., 7., 8., 9. };
    

    Schreib mal eine funktionierende Version Deines Algorithmus' zur Mittelwertbestimmung fuer das Array values . Zur Kontrolle: Ergebnis ist 4.5.



  • @Furble: Ich denke, es geht um eine gleitende Mittelwertbildung.



  • @Caligulaminus:
    prinzipiell hat Bashar ja schon alles gesagt.
    Aber wenn ich mir den Code oben ansehe funktioniert noch nicht mal der einfache Durchschnitt - wie soll es da erst werden, wenn das Array unterschiedlich groß ist, bzw. sich Werte im Array aendern.
    Eine einfache Teilaufgabe (schreib eine Funktion, die den Mittelwert eines Arrays errechnet) schien mir da ein passender erster Schritt.



  • Furble Wurble schrieb:

    [..]Eine einfache Teilaufgabe (schreib eine Funktion, die den Mittelwert eines Arrays errechnet) schien mir da ein passender erster Schritt.

    OK

    double funktion(double wert)
    {
      for(int i = wert;...
    

    Das hat mich verwirrt.



  • Ja es handelt sich um c++.

    Hier mein Code, ich habe ihn in main() geschrieben um das Programm ausführen zu können und es ist 4.5 rausgekommen:

    double values[10] = {0,1,2,3,4,5,6,7,8,9};
    double summe = 0, mittelwert;
    int i;

    for(i=0; i<10; i++)
    {

    summe += values[i];

    }

    mittelwert = summe/10;
    cout << "Mittelwert: " << mittelwert << endl;



  • Ich find die Aufgabe uebrigens nicht so gelungen - weil Du entweder globale Variablen oder etwas fortgeschritteneres Knowhow von C++ brauchst.

    Egal. Das Problem ist, dass Deine Funktion ja eigentlich kein "Gedaechtnis" fuer die vorherigen Werte hat - wenn Du dort Variablen anlegst werden die am Ende der Funktion wieder getilgt und beim naechsten mal neu angelegt.

    Variablen ueber mehrere Funktionsaufrufe zu behalten geht allerdings, wenn Du sie als static deklarierst - hat Bashar ja auch schon gesagt.

    Hier z.B. eine Funktion, die bei jedem Aufruf einen Wert in ein Array schreibt, bzw. wenn das Array voll ist dieses ausgibt:

    #include <iostream>
    #include <iterator>
    
    void insert(int i){
      static int arr[3]={};             // ein static array
      static auto p = std::begin(arr);  // ein static Iterator auf dessen Anfang
      if(p!=std::end(arr))
      	*p++=i;
      else
        for(int ii : arr)
          std::cout << ii << ' ';
    }
    
    int main(){
    	insert(10);
    	insert(20);
    	insert(30);
    	insert(40);
    }
    

    Ausgabe

    10 20 30
    

    D.h. sowohl arr als auch p wurden nur einmal initialisiert und behielten danach ueber mehrere Funktionsaufrufe ihre Werte.

    Das ist prinzipiell alles was Du brauchst.
    Deine Aufgabe ist schwerer, weil komplexer, aber mit etwas Gehirnschmalz schaffbar.

    Wenn Du irgendwann die Werte in Deinem Array shiften musst, koennten rotate() oder move() aus <algorithm> interessant sein.

    PS: oben benutze ich C++11 - es geht aber prinzipiell genau so auch in C++98.



  • @Furble Wurble
    hmmm globale Variablen geht ja nicht weil es ja hier nur um eine Funktion geht. Von static habe ich schon gelesen, aber die ganzen anderen Sachen sind mir komplett neu, steht also nicht in meinen Unterlagen, wesewegen es mich verwundert dass es so gehen soll.

    Ich habe mal deinen Code kopiert, aber bein kompilieren traten eine Menge Fehlermeldungen auf.

    Hier nochmal eine Anmerkung vom Aufgabensteller:
    also wie die aktuellen wert ins array[15] stopfen ... oder besser gesagt auf welche der fünfzehn speicherzellen soll der aktuelle wert?



  • c++123 schrieb:

    @Furble Wurble
    hmmm globale Variablen geht ja nicht weil es ja hier nur um eine Funktion geht. Von static habe ich schon gelesen, aber die ganzen anderen Sachen sind mir komplett neu, steht also nicht in meinen Unterlagen, wesewegen es mich verwundert dass es so gehen soll.

    Ich habe mal deinen Code kopiert, aber bein kompilieren traten eine Menge Fehlermeldungen auf.

    Zur Erklaerung: vor zwei Jahren wurde einige Veraenderungen an C++ vorgenommen (C++11). Wenn Dein Skript das nicht widerspiegelt und Dein Compiler das nicht kompiliert(*) sind beide nicht mehr bleeding edge. 🙂
    Aber das ist nicht schlimm.

    Hier das gleiche nochmal mit Features, die z.T. seit 40 Jahren funktionieren:

    // gleicher Code, C++98 Version
    
    #include <iostream>
    #include <iterator>
    
    void insert(int i){
      const size_t N = 3;
      static int arr[N]={}; // ein static array
      static int* p = arr;  // ein static int* auf dessen Anfang
      if(p!=arr+N)
        *p++=i;
      else
        for(const int* pp=arr; pp!=arr+N; ++pp)
          std::cout << *pp << ' ';
    }
    
    int main(){
        insert(10);
        insert(20);
        insert(30);
        insert(40);
    }
    

    Jetzt lesbarer?

    c++123 schrieb:

    Hier nochmal eine Anmerkung vom Aufgabensteller:
    also wie die aktuellen wert ins array[15] stopfen ... oder besser gesagt auf welche der fünfzehn speicherzellen soll der aktuelle wert?

    Das ist doch Dir ueberlassen, wo Du den Wert einfuegst!? Wichtig ist halt, dass Du den Wert, den Du 15 Durchlaeufe vorher eingelesen hast nicht mehr in die Mittelwertberechnung einbeziehst. Ich koennte mit diesen ominoesen Tipps nichts anfangen...

    Wie gesagt:
    Prinzipiell kannst Du das Geruest oben aufbohren um die Aufgabe zu erledigen.

    Ich ueberlege, wie ich noch helfen kann, aber wenn ich jetzt eine Mittelwertberechnung ueber den Bereich [&arr[0], p) einfuege kann ich auch gleich eine Komplettloesung schreiben, oder?
    Wenn's immer noch nicht klingelt musst Du mir verraten, was Du bisher gelernt hast...

    (*) Beim Compiler gibts evtl. einen Schalter, der C++11 Support aktiviert.



  • Furble Wurble erst mal Danke für die Große Mühe die du dir machst! 👍

    Ja den zweiten code kann ich besser nachvollziehen, aber auch noch nicht 100%.

    Zeile 7: Ich gehe davon aus, dass das gleichwertig mit dem gegebenen #define Fenster 15 ist.

    Zeile 8: Das Array wurde mit static definiert, warum habt ihr ja schon geschrieben.

    Zeile 9: Ein Zeiger wurde auf das Array initialisiert. (Ist Static hier aus dem selben Grund Pflicht wie beim Array selbst?)

    Zeile 10: Eine if-Bedingung wurde formuliert mit der Bedingung: Wenn p ungleich Array+Arraygröße, also bei deinem Bsp., p ungleich 3.

    Zeile 11: Wenn die if-Bedinung erfüllt ist wird der Zeiger inkrementiert und dem Funktionsparameter, hier i, zugeordnet.

    Zeile 12/13: Falls die if-Bedinung nicht erfüllt ist geht es in eine for-Schleife. Den Schleifenkopf verstehe ich nicht, vor allem warum wird hier als pp und unten *pp geschrieben, anstatt p und *p?

    Tja als Lehrmaterial hatten wir hauptsächlich das Buch C++ Programmieren mit einfachen Beispielen von Dirk Louis. Es enthält würde ich sagen so die Basics ohne in die Tiefe zu gehen. In unseren Lehrheften ging es dann eher um C. Hier kamen auch dann noch Themen wie Zeiger und mehrdimensionale Felder, was im Buch z.B. fehlt.



  • c++123 schrieb:

    Zeile 7: Ich gehe davon aus, dass das gleichwertig mit dem gegebenen #define Fenster 15 ist.

    Ja. Makros sind im großen und ganzen verpönt. Z.B. weil die den globalen Namensraum 'verschmutzen'.
    N hingegen ist nur innerhalb der Funktion insert() gueltig.
    Siehe z.B. hier:

    void func(){
    #define FENSTER 15;
    }
    
    int main(){
      return FENSTER; // huh? Makro FENSTER hier auch gueltig
    }
    

    c++123 schrieb:

    Zeile 9: Ein Zeiger wurde auf das Array initialisiert. (Ist Static hier aus dem selben Grund Pflicht wie beim Array selbst?)[...]
    Zeile 10: Eine if-Bedingung wurde formuliert mit der Bedingung: Wenn p ungleich Array+Arraygröße, also bei deinem Bsp., p ungleich 3.

    Der Zeiger p gibt ja bei jedem Funktionsaufruf die Stelle an, an die eingefügt wird. Er ist sozusagen Einfügemarke und Füllstandsindikator. Damit wir den Marker über mehrere Funktionsaufrufe nicht verlieren muss der auch static sein.
    Wenn p an der Stelle arr+N angelangt ist, "ist das array voll". p wird nicht gleich drei sein, sondern irgendeinen Wert haben (je nachdem wo arr im Speicher liegt).
    Z.B. Wenn arr an der Adresse 100 im Speicher liegt:

    100  101  102  103 ...
    +----+----+----+---~
    | xx | yy | zz |
    +----+----+----+---~
    ^              ^
    |              |
    arr            p
    

    Das Array ist also voll, wenn der Zeiger auf "eins hinter das Array" zeigt - das ist ganz typisch für die Arbeit mit Sequenzen in C++.

    c++123 schrieb:

    Zeile 11: Wenn die if-Bedinung erfüllt ist wird der Zeiger inkrementiert und dem Funktionsparameter, hier i, zugeordnet.

    Obacht: Die Zuweisung wird auf den dereferenzierten Zeiger angewandt. Danach wird der Zeiger inkrementiert. Ganz klassisch - wird auf jeden Fall irgendwo z. Thema Zeiger und arrays in Deinem Buch behandelt.

    c++123 schrieb:

    Zeile 12/13: Falls die if-Bedinung nicht erfüllt ist geht es in eine for-Schleife. Den Schleifenkopf verstehe ich nicht, vor allem warum wird hier als pp und unten *pp geschrieben, anstatt p und *p?

    pp ist eine neue Variable. Die auch p zu nennen wäre verwirrend. Der Schleifenkopf beinhaltet kein Geheimnis. Sieht immer so oder ähnlich aus. 😉

    Für Deine Aufgabe kannst Du jetzt ein array nehmen und einen Zeiger - ganz so wie oben.
    Wenn Du einen neuen Wert bekommst schreibst Du den an die Stelle auf die der Zeiger zeigt und bewegst den Zeiger weiter.
    Dann berechnest Du den Mittelwert der jetzt im Array stehenden Zahlen und gibst ihn zurück.

    Etwas dusselig ist jetzt die Stelle, wenn Dein Array voll ist. Du könntest dann vor dem einfügen alle Zahlen im Array eins nach vorne schieben, d.h. der erste Wert fiele aus der Berechnung raus.


Anmelden zum Antworten