C++ Wav-Datei Samples addieren



  • @Berkan046
    new ... besorgt Dir Speicher auf dem Heap und gibt Dir einen Zeiger darauf zurück.
    In Deiner if - Abfrage machst Du nichts damit, der Speicher wird für Dich reserviert, aber Du speicherst den Zeiger, den Dir new zurück gibt, nicht.
    Du hast also keinen Zugriff mehr auf diesen Speicher, er ist für Dein Programm verloren, insbesondere kannst Du ihn nicht mehr freigeben.
    Und das passiert jedes Mal, wenn Dein Container mehr Speicher benötigt.



  • @Belli Ok danke das du es erklärst. Soweit ich bisher es gelesen habe, meintest du, dass mein double myArray unnötig ist. Müsste ich statt double mein Template T verwenden? Und bei der If-Abfrage wäre es ja sinnvoll nur abzufragen, ob mein myArray == NULL ist oder nicht?



  • Beides ja.
    Warum mySize vom Typ T ist erschließt sich mir nicht.



  • Jo, siehe vorletzter Satz in Aufgabe 1:
    'Das Array soll vom Template Datentyp sein, also beliebige Datentypen fassen können.'
    Aktuell fasst Dein 'Array' Zeiger auf double ...
    Und wie Swordfish schon angemerkt hat: Deine Variable mySize, und alles was mit size zu tun hat, soll ja sicher speichern, für wieviel Einträge Du Speicher beschafft hast/beschaffen willst. Da ist der Datentyp T fehl am Platze.



  • @Berkan046 sagte in C++ Wav-Datei Samples addieren:

    @hustbaer Ich gebe dir vollkommen Recht. Nur macht es ebenso wenig Sinn zu sagen das es falsch ist, statt kurz und knapp zu sagen was falsch ist. Und wenn alles nicht stimmt, dann kann man das auch direkt sagen finde ich.

    Es geht darum dass du verstehen musst was der Code macht den du schreibst. Du musst zumindest eine Vorstellung davon haben was du damit bezwecken möchtest wenn du sowas wie if (ptr != NULL && new double[size])schreibst.
    Wenn du eine Vorstellung davon hast, dann kannst du diese erklären und wir können dich ggf. korrigieren.
    Und wenn du einfach etwas hinschreibst ohne eine Vorstellung davon zu haben was du damit erreichen willst, dann ist genau das das Problem. So kann man nicht programmieren.

    Auch macht der && new double[size] Teil sowas von überhaupt keinen Sinn, dass es gut wäre zu wissen warum du es geschrieben hast. Denn irgendwas hast du dir ja dabei gedacht. Das weist auf ein recht grundlegendes Misverständnis hin. Und dieses zu korrigieren wäre denke ich wichtig.

    Immer gleich zu schreiben was falsch ist, ist mMn. gerade nicht der beste Weg jemandem das Programmieren beizubringen.



  • @Belli danke dir. Mittlerweile merke ich, dass ich den Code hätte schicken sollen, bevor ich verzweifelt war und nach Lust und Laune es geändert habe.



  • @hustbaer Ja wie gesagt ich geben dir 100% Recht, aber ich bin gerade so verzweifelt, dass ich fast gar nichts mehr verstehe. Mein Code wurde erst im nachhinein so "beschissen", nachdem ich versucht habe die wave-Datei irgendwie in mein Array zu speichern und dabei vieles rumprobiert habe. Ich werde jetzt erstmal alles wieder "korrigieren".
    Aber ich danke dir vielmals 😊.



  • @Swordfish Danke für deine Antwort. Da wo du es sagst ist es mir auch aufgefallen, bin am Ende gewesen mit der Aufgabe, so dass ich versucht haben nach Lust und Laune alles umzustellen, dass es irgendwie mit Glück klappt. 😅


  • Mod

    @Berkan046 sagte in C++ Wav-Datei Samples addieren:

    @hustbaer Ja wie gesagt ich geben dir 100% Recht, aber ich bin gerade so verzweifelt, dass ich fast gar nichts mehr verstehe. Mein Code wurde erst im nachhinein so "beschissen", nachdem ich versucht habe die wave-Datei irgendwie in mein Array zu speichern und dabei vieles rumprobiert habe. Ich werde jetzt erstmal alles wieder "korrigieren".

    Auch das ist eine Erkenntnis (zumindest für dich): Die Strategie funktioniert nicht. Wenn man an nicht-funktionierendem Code verständnislos herumändert wird der Code dadurch niemals zufällig funktionsfähig. Dazu nimmt ein Computer alles viel zu wortwörtlich und es gibt exponentiell mehr nicht-funktionierenden Code als funktionierenden. Die einzig funktionierende Strategie in solchen Fällen ist, das eigene Verständnis zu steigern.

    Herumprobieren funktioniert nur dann, wenn man im Verständnis schon so weit ist, dass man gezielt eine kleine Menge von Möglichkeiten durchprobieren kann. Dann ist das durchaus eine bewährte (aber leicht verpönte) Methode.



  • So das ist jetzt der neuste Stand vom Code.

    #include <iostream>
    #include <stdio.h>
    #include <stdlib.h>
    
    template <class T>
    
    class Container{
    	
    	private:
    		T *myArray;
    		int mySize;
    		
    	public:
    		
    		Container(unsigned int startSize){
    			mySize = 0;
    			myArray = NULL;
    			resize(startSize);		
    		}
    	
    		~Container(){
    			if(myArray != NULL){
    				delete[] myArray;
    			}
    		}
    		
    		
    		void resize(unsigned int size){
    		
    			T *newArray =  new T[size];
    			int t = 0;
    			if(myArray != NULL){
    				for(t = 0; (t < size) && (t < mySize); t++){
    					newArray[t] = myArray[t];
    				}
    				for(; t < size; t++){
    					newArray[t] = 0;
    				}
    				
    				delete[] myArray;
    			}
    			
    			myArray = newArray;
    			mySize = size;
    			
    		}
    		
    		T &operator[](unsigned int index){
    			
    			if(index < 0)
    				printf("Index negativ \n");
    			
    			if(index > mySize)
    				resize(index + 1000);
    				
    			return myArray[index];
    			
    		}
    };
    
    

    Nun verstehe ich nicht wieso im Konstruktor mein myArray = NULL gesetzt wird und später in der resize-Methode es auf NULL überprüft. Ich meine es ist ja dann immer NULL durch den Konstruktor oder nicht?
    Und wieso wird nirgendwo die &operator[]- Methode aufgerufen bzw. diese Methode verstehe ich nicht, bis auf dass es die rezise-Methode aufruft, um den neuen Array zu vergößern?


  • Mod

    Was ist, wenn resize ein zweites Mal aufgerufen wird?

    Dass die Methoden deines Containers nirgendwo benutzt werden, ist ja kein Wunder, solange du deinen Container nirgendwo benutzt.



  • @SeppJ Wenn die resize-Methode ein zweites mal aufgerufen wird, dann wird mein Index+1000 übergeben und anschließend newArray[index+1000] bzw. newArray[size] initialisiert. Danach werden die Werte vom erstenArray in das zweite Array übertragen.

    Das heißt, dass die Operator-Methode immer aufgerufen wird oder wie?



  • Eigentlich sieht das gar nicht so schlecht aus, nur das Verhalten des []-Operators ist etwas merkwürdig. Normalerweise vergrößert der Aufruf den Container nicht, sondern wirft ´ne Exception oder sowas.
    Welchen C++ Standard benutzt du? Kann dein Compiler schon min. C++11? Wenn ja kannst du die Initialisierung schon in den Header verschieben:

    template<typename T>
    class Container
    {
       T* myArray = nullptr;
       int mySize = 0;
       ...
    }
    

    Die Zuweisung in Zeile 37 funktioniert nur für numerische Datentypen, wenn du zB std::string in deinem Container speichern möchtest erzeugt die Zeile einen Fehler. Du kannst stattdessen newArray[t] = T{}; schreiben, damit wird der default-Konstruktor des jeweiligen Datentyps benutzt. Für numerische Werte liefert der 0, abhängig vom Datentyp (also auch 0.0 und 0.0f).

    Ich persönlich würde ja für die Anzahl der Elemente und den Index einen positiven Ganzzahltypen nehmen, dann kann man sich die Überprüfung auf < 0 schenken.

    PS:
    Ne Überprüfung des Rückgabewerts von new brauchst du nicht, der ist immer gültig oder es wird ein std::bad_alloc geworfen.

    PPS:
    In deiner resize Methode lässt du negative Größen zu.



  • @DocShoe Danke dir. Ich bin mir da nicht sicher, aber ich glaube mein Prof. meinte, dass wir kein C++ 11 benutzen. Er hat auch auf seiner Seite ein extra Video zu C++ 11 und deswegen gehe ich davon aus, dass wir es nicht benutzen.



  • Habe nun mein Code oben geupdatet (kleine Änderungen).

    Jetzt ist mein Problem (wie ganz am Anfang): Wie lade ich meine Wave-Datei in mein Container?

        FILE  *myFile;
        myFile = fopen("song.wav", "rb");
        
         //Container <FILE> wavArray(1000);
    
        return 0;
    
    

    Das ist der Code wie ich es vorhätte, also <FILE> anzugeben, aber dann kommt wiederum ein Fehler in der Container Klasse.



  • @Berkan046
    FILE ist der Descriptor/Handle der Datei, das ist nicht der Dateiinhalt. Du musst jetzt den Inhalt der Datei lesen und dir überlegen, was du eigentlich in deinem Container ablegen möchtest.



  • @DocShoe vielleicht so:

        Container <char> wavArray(1000);
        FILE  *myFile;
        myFile = fopen("song.wav", "rb");
        
        if(myFile){
    		for(int index = 0; index < 1000; index++){
    			wavArray.myArray[index] = fgetc(myFile);
    		}
    
    


  • @Berkan046
    Ja, vielleicht. Vielleicht auch nicht. Keine Ahnung, das musst du doch wissen.

    Du liest immer genau 1000 Zeichen ein, was ist, wenn die Datei kürzer oder länger ist? Schlauer ist es, zuerst die Länge der Datei zu bestimmen und dann genauso viele Zeichen zu lesen.
    Wenn du mit deinem Container weiterarbeiten möchtest wäre eine size() Methode sinnvoll.

    Edit:
    Ne, dein Schnipsel kann nicht funktionieren. myArray ist privat, da kommste von außen nicht dran. Fängst du jetzt wieder an zu raten?



  • @DocShoe Nein habs gelesen, dass es private sei, ich habe es auf public umgeändert. Danke dir für den Tipp mit der Länge, aber ich habe es so verstanden gehabt, dass in meine Container Klasse mein Array immer automatisch vergrößert.

    PS: Ich habe jetzt erstmal alle Atributte auf public umgeändert.



  • @Berkan046
    Ganz schlechte Idee. Ganz schlecht. Wirklich. Lass die Implementierung privat und benutz´ die öffentliche Schnittstelle. Dadurch, dass du direkt auf den Rohspeicher statt des []-Operators zugreifst vergrössert sich dein Array nicht automatisch. Wie SeppJ schon sagte: Du musst genau wissen, was du tust, und nicht einfach rumraten und Codeschnipsel hin- und herschieben bis der Compiler keine Fehler mehr meldet.


Anmelden zum Antworten