Dynamische Speicherallokation und Arrays



  • Hallo zusammen,

    ich fange gerade neu mit C++ und Programmieren überhaupt an und kämpfe mich momentan durch ein paar Übungsaufgaben. Bei der folgenden komm ich nicht weiter.
    Erst mal die AUfgabenstellung:

    ********

    Erstellen Sie eine C++-Anwendung, in der Sie dynamisch ein eindimensionales Array vom Typ short erstellen. Der Anwender Ihres Programms soll angeben können, aus wie vielen Elementen das Array bestehen soll. Legen Sie abwechselnd in alle Elemente des Arrays die Zahlen 0 und 1 hinein und geben Sie danach den Inhalt des Arrays auf den Bildschirm aus.

    *********

    und das folgende ist mir dazu eingefallen:

    #include <iostream>
    using namespace std;
    
    int main()
    {
    
    	cout << "Aus wie vielen Stellen soll das Array bestehen?" << endl;
    	char anzahl[20];
    	cin >> anzahl;
    	int anz = atoi(anzahl);
    
    	short*  aray1 = new short[anz];
    
    	cout << aray1 << endl;
    
    	for (int i=0; i<anz; i++)
    	{
    		int z=i%2;
    		short* a = &aray1[i];
    
    		if(z==0)
    			*a = 0; //alternativ aray1[i] = 0; Funzt aber auch nicht
    		else
    			*a = 1;
    
    	}
    	delete[] aray1;
    
    	cout << aray1 << endl;
    
    	system("PAUSE");
        return EXIT_SUCCESS;	
    
    }
    

    Als Ausgabe erhalte ich immer so was wie 00356320. Unabhängig davon was ich bei cin eingebe.

    Vielen Dank für eure Hilfe.



  • Ich sehe zwei Probleme:
    Du löscht aray1, bevor Du es ausgibst.
    Du gibst nur das Array aus (welches implizit ein Zeiger auf das erste Element interpretiert wirtd), nicht den Inhalt. Falls Du erwartest, dass C++ das automatisch macht: Das tut es nicht, Du wirst zum Ausgeben auch eine Schleife gebrauchen.

    Davon ganz abgesehen, woher sind die Aufgaben? Aus einem Buch? Wenn ja, scheint der Autor (mal wieder) der Ansicht zu sein man müsse Anfänger unbedingt gleich mit Zeichenarrays und Zeigern konfrontieren.

    - Benutze std::string!
    - Benutze std::vector!



  • #include <iostream>
    using namespace std;
    
    int main()
    {
    
    	cout << "Aus wie vielen Stellen soll das Array bestehen?" << endl;
    	char anzahl[20]; // besser wäre std::string
    	cin >> anzahl;
    	int anz = atoi(anzahl); // atoi() ist eine C-Funktion; Alternative: std::stringstream
    
        short*  aray1 = new short[anz];
    
    	cout << aray1 << endl; // du gibst den Zeiger aus
    
    	for (int i=0; i<anz; i++)
    	{
    		aray1[i]=i%2; // Direkte Zuweisung
    
            // von hier ...
            //short* a = &aray1[i];
    
    		if(z==0)
    			*a = 0; //alternativ aray1[i] = 0; Funzt aber auch nicht
    		else
    			*a = 1;
            // ... bis hier ist alles überflüssig
    
    	}
    	delete[] aray1; // hier löschst du das Array
    
    	cout << aray1 << endl; // hier greifst du noch darauf zu -> undefiniertes Verhalten
    
    	system("PAUSE");
        return EXIT_SUCCESS;	// unnötig
    
    }
    

    HaleBob schrieb:

    Als Ausgabe erhalte ich immer so was wie 00356320. Unabhängig davon was ich bei cin eingebe.

    Vielen Dank für eure Hilfe.

    Das wundert mich nicht, du gibst ja auch nicht die einzelnen Elemente Stück für Stück aus, sondern den Zeiger auf das Array. Du musst in einer Schleife die einzelnen Elemente durchgehen:

    for (short i = 0; i < anzahl; i++)
    {
       cout << aray1[i] << endl;
    }
    


  • Weil ich gerade Langeweile habe, hier mal ein Lösungsvorschlag, der ganz ohne Zeiger auskommt. Es fehlt aber die Fehlerbehandlung nach der Eingabe der Zahlen (wo Dein Programm dafür ungeprüft mit dem Wert 0 weiterrechnen würde):

    #include <iostream>
    #include <vector>
    using namespace std; 
    
    int main() 
    { 
        cout << "Aus wie vielen Stellen soll das Array bestehen?" << endl; 
    
        int anzahl;
        cin >> anzahl;
    
        // short*  aray1 = new short[anz];
        // ->
        vector<short> array1(anzahl, 0);
    
        // so nicht:
        // cout << aray1 << endl; 
        // ->
        for (int i = 0; i < array1.size(); ++i) {
            cout << array1[i] << endl;
        }
    
        for (int i = 0; i < array1.size(); ++i) {
            int z = i % 2;
    
            // Warum die Indirektion? Geht zwar auch, auch mit vector, aber gerade bei einmaliger Anwendung reicht der direkte Zugriff vollkommen.
            // short* a = &aray1[i]; 
    
            // Wenn, dann aber per Referenz:
            short& a = array1[i];
            if (z == 0) 
                a = 0; // alternativ array1[i] = 0
            else 
                a = 1; 
        } 
    
        // NICHT erforderlich. Vector kümmert sich selbst um seinen Speicher
        // delete[] aray1; 
    
        // siehe oben
        // cout << aray1 << endl;
    
        // return am Ende von main nicht erfoderlich. Stört aber auch nicht.
    }
    

  • Mod

    Nexus schrieb:

    char anzahl[20]; // besser wäre std::string
    	cin >> anzahl;
    	int anz = atoi(anzahl); // atoi() ist eine C-Funktion; Alternative: std::stringstream
    

    ...macht mich fast sprachlos, der Vorschlag
    Man kann (und sollte) Zahlen direkt aus der Eingabe lesen und nicht diesen umständlichen Weg über String+Umwandlung wählen - dann kommt es gar nicht darauf an, wie gut oder schlecht die Umwandlung durchgeführt wurde.

    int anz = 0;
    cin >> anz;
    

  • Mod

    So problematisch die allzu frühe Einführung dynamischer Speicherverwaltung sein mag: vector und co. lösen die Aufgabe nicht so, wie sie gestellt wurde.



  • camper schrieb:

    So problematisch die allzu frühe Einführung dynamischer Speicherverwaltung sein mag: vector und co. lösen die Aufgabe nicht so, wie sie gestellt wurde.

    Du hast recht, da habe ich zu wenig auf den Aufgabentext geachtet. Aber wenigstens kann man dem Vector einen Zeiger auf ein eindimensionales Array vom Typ short entnehmen.



  • WOW, das ging ja schnell. Das muss ich jetzt erst mal auseinanderpflücken.
    Beim ersten drüberschauen hab ich den eindruck, daß ich bei der Speicherallokation was grundsätzliches nicht kapiert habe.

    Davon ganz abgesehen, woher sind die Aufgaben? Aus einem Buch? Wenn ja, scheint der Autor (mal wieder) der Ansicht zu sein man müsse Anfänger unbedingt gleich mit Zeichenarrays und Zeigern konfrontieren.

    - Benutze std::string!
    - Benutze std::vector!

    Von hier:http://www.highscore.de/cpp/einfuehrung/index.html
    Der Autor schreibt schon ganz am Anfang, daß idR strings verwendet werden. Das hier macht er wohl...na ja...zur Übung 😃

    Vektoren waren auch noch nicht dran.

    Daß aray1 ein Zeiger ist und nicht mein array war mir nicht ganz klar, das heißt also, daß ich mir die Spiecheradresse des ersten Elements anzeigen lasse??

    cout << aray1 << endl; // du gibst den Zeiger aus
    

    Hier wollte ich nur mal sehen, was vor dem neu Beschreiben im array liegt. Das gleiche wie am Ende 😃
    Jetzt wieß ich auch warum.

    Kann mir vielleicht mal jemand die Zeile hier zerpflücken:

    short*  aray1 = new short[anz];
    

    Wird hier nur ein Zeiger definiert? Wo wird dann das array erstellt?

    aray1[i]=i%2; // Direkte Zuweisung
    

    Da wäre ich in 100 Jahren nicht drauf gekommen, aber so ist das mit dem Wald und den Bäumen eben.

    int anz = 0;
    cin >> anz;
    

    Bisher wurde (im Buch) ausschließlich über cin.get() in chars eingelesen. Ich glaub das hab ich mal für int probiert, ging aber nicht. Über cin>> bin ich irgendwo mal gestolpert und hab es dann verwendet, wohl ohne genau zu wissen was ich da mache und daß es auch für int funktioniert, daher die Umwandlerei. Könnte mich aber auch täuschen und ich hatte einen anderen Fehler drin. Wie gesagt, bin noch ganz am Anfang.

    Auf jeden Fall vielen Dank an alle, ich geh jetzt mal ein paar Fehler ausmerzen.



  • HaleBob schrieb:

    Kann mir vielleicht mal jemand die Zeile hier zerpflücken:

    short*  aray1 = new short[anz];
    

    Wird hier nur ein Zeiger definiert? Wo wird dann das array erstellt?

    Man könnte das auch in zwei Zeilen schreiben:

    short*  aray1; // Deklaration des Zeigers
    aray1  = new short[anz]; // Reservierung des Speichers und Zuweisung der ersten Adresse des Arrays an aray1
    

    Reicht das?



  • camper schrieb:

    Nexus schrieb:

    char anzahl[20]; // besser wäre std::string
    	cin >> anzahl;
    	int anz = atoi(anzahl); // atoi() ist eine C-Funktion; Alternative: std::stringstream
    

    ...macht mich fast sprachlos, der Vorschlag
    Man kann (und sollte) Zahlen direkt aus der Eingabe lesen und nicht diesen umständlichen Weg über String+Umwandlung wählen - dann kommt es gar nicht darauf an, wie gut oder schlecht die Umwandlung durchgeführt wurde.

    int anz = 0;
    cin >> anz;
    

    Und was machst du, wenn eine Fehleingabe (z.B. ein Buchstabe) vorliegt? Oder kann man das direkt über den Eingabestream cin überprüfen? Ich kenne mich drum nicht wirklich mit dem aus, ich benutze schon ewig keine Konsole mehr 😉

    HaleBob schrieb:

    short*  aray1 = new short[anz];
    

    Wird hier nur ein Zeiger definiert? Wo wird dann das array erstellt?

    Mit new short[anz] wird ein dynamisches Array erstellt. Das new fordert dabei Speicher auf dem Heap (dynamischer, manuell verwalteter Speicherbereich) an. Wenn du aber folgendes schreibst:

    short *array1;      // Nur Deklaration und Definition; Zeiger zeigt irgendwo hin
    array1 = new short[anz]; // Initialisierung: Jetzt zeigt der Zeiger auf ein Array im Heap (bzw. 1. Element)
    

    Und nutze in Zukunft bitte C/C++- statt Code-Tags.

    Edit: Sorry für die Wiederholung... Da hatte ich tatsächlich so lange an dem Beitrag? 😃



  • Nexus schrieb:

    Und was machst du, wenn eine Fehleingabe (z.B. ein Buchstabe) vorliegt? Oder kann man das direkt über den Eingabestream cin überprüfen? Ich kenne mich drum nicht wirklich mit dem aus, ich benutze schon ewig keine Konsole mehr 😉

    int anz = 0;
    std::cin >> anz;
    if(std::cin.fail ())
    {
        std::cin.clear ();
        std::cin.ignore ();
    }
    
    std::cout << anz;
    

Anmelden zum Antworten