Problem bei der Ausgabe (Dynamische Speicherverwaltung)



  • es lag daran, dass ich bereits das delete mit dazu genommen hab, da aber wohl n fehler drin habe.

    habe den delete befehl in die letzte for-schleife gepackt, aber was stimmt denn an der programmierung nicht, hab schon alles ausprobiert, ohne index, mit index, etc.

    for (int x=0; x<n; x++)
    	{	cout << "\n\nName, Person " << x << ":\t\t";
    		cout << (Personen + x)->Name ;
    		cout << "\nNummer, Person " << x << ":\t";
    		cout << (Personen + x)->Nummer ;
    		delete Verwaltung[x];
    	}
    


  • sarah1986 schrieb:

    delete Verwaltung[x];
    

    Die anweisung als solche ist schon unsinnig (sag blos, das hat dein Compiler geschluckt) - 'Verwaltung' ist der Typ. Du mußt deine Variable löschen und zwar als ganzes:

    for(int x=0; x<n; x++)
    {
      //Ausgaben
    }
    delete[] Personen;
    


  • DA liegt der fehler groß groß^^ 🤡

    Du hast mit new[] ein Feld dynamisch angelegt, dieses kannst du nun auch nur wieder als ganzes mit delete[]freigeben

    new <-> delete
    new[] <-> delete[]

    Also mache das

    delete[] Personen;
    

    nachdem zu das Feld nicht mehr benötigst, ergo nach der zweiten for-Schleife



  • so ähnlich hatte ich es auch, nur die eckigen klammern hinter dem personen... das ging net. aber so läufts hoffentlich. tausend dank



  • gibt es die möglichkeit mein programm so zu erweitern, dass ich die abfrage zuvor, wieviele datensätze ich anlegen will, weglasse, und durch irgendne bedingung dann aufgehört wird, wie beispielsweise ein ausrufezeichen.



  • Ja, allerdings wird die Speicherverwaltung dann schwieriger (weil du vorher wissen mußt, wieviel Platz du brauchst - da müsstest du den belegten Platz in regelmäßigen Abständen reorganisieren). Oder du könntest umsteigen auf STL-Container (vector oder deque).



  • da reichen meine bisherigen kenntnisse nicht aus, dann lass ich es dabei, trotzdem vielen dank



  • GPC schrieb:

    Oder so (du willst ja bestimmt den ganzen Namen):

    getline(cin, (*(Personen+x)).Name);
    //getline(cin, (Personen+x)->Name);
    

    EDIT: Pellaeons Lösung geht auch, da man Pointer wie Arrays behandeln kann, und umgekehrt.
    EDIT2: Klammern einfügt

    habe mich jetzt nochmal an das prog gesetzt, und versuche alles zu verstehen. was bewirkt dieses +x genau? Muss ich das unbedingt benutzen?

    Dann habe ich noch ne Frage:
    In der Berufsschule haben wir ein Aufgabenblatt zur Dyn. Speicherverwaltung bekommen. (Verwaltung von Artikeln) Dort steht:

    Als Datenstruktur soll ein 1-dimensionales Array mit Pointern vom Typ T_Artikel gewählt werden, was somit einer halbdynamischen Datenstruktur eintspricht: das Pointer-Array ist statisch, die eigentlichen Artikeldaten werden dynamisch angelegt.

    Was ist damit gemeint? - Ist das das gleiche, wie ich bei meinem Prog verwendet habe oder wieder etwas anderes?



  • also das "+ x" dort hat mit Zeigeraritkemtik zu tun.

    "Personen" ist dein Feld. Bei Feldern ist der Name ein Zeiger auf das erste Element im Feld, also die 0.te Stelle sozusagen.
    Bei Feldern liegen die Elemente zusammenhängend hintereinander im Speicher, deswegen ja ein Feld 🙂
    Wenn du jetzt auf das zweite Element zugreifen willst, musst du dich im Feld weiter bewegen. Ein int ist z.B. normalerweise momentan 4 Byte groß. Du müsstes dich also um 4 Adressen weiter bewegen von der Startadresse aus.
    C++ ist jedoch clever, jetzt kommt nämlich die Zeigerarithmetik ins Spiel.
    Wenn du einen Zeiger + 1 machst, springt er nicht einfach ein Byte weiter, sonder es wird nachgeschaut, von welchem Typ der Zeiger ist und dann wird eine Variable weiter gesprungen. Also am Beispiel hier der erkennt "aha ich zeige auf ein int, int ist 4 Byte groß, also muss ich bei + 1 4 Byte weiter gehen im Feld.

    Also sorgt die Zeile (Personen + x) das er die Adresse des x.ten Elements berechnet. Und wenn du nun die Adresse des x.ten Elements hast, kannst du damit arbeiten.

    Zu deiner 2. Frage:

    Du sollst ein Array von Pointern machen, also

    T_Artikel* zeigerFeld[100];
    

    In der Aufgabe steht statisch, also ohne new machen udn einfach nen festen wert abgeben.



  • aber wenn ich das ohne das +1, sondern mit

    Personen[x].Name;
    

    mache funzt es ja genauso.

    ich dachte, das funzt nur mit new, da ich sonst keinen speicherplatz habe, jetzt SOLL ich es ohne new machen????
    da steig ich nicht durch.
    Wie soll denn der entsprechende Speicherplatz reserviert werden, wenn ich kein new verwende???
    Wann benutze ich dann new und wann nicht?



  • siehe Aufgabenstellung:
    Wenn du die Anzahl zur Compilezeit kennst(oder wenns halt vom Lehrer/Prof vorgegeben ist^^), dann machst du ein statisches Array.
    Wenn die Anzahl jedoch beim Kompilieren unbekannt ist, und erst während der Laufzeot ermittelt wird(wie auch immer: eingabe oder Berechnung oder was weis ich ...) dann musst du new benutzen.

    "Personen[x].Name" ist äquivalent zu "(Personen + x)->Namen", zumindest in deinem konkreten Fall.
    Bei dem statischen Array von Zeigern sieht der Zugriff schon wieder anders aus, weil die Typen anders sind.



  • dann werd ich das mal so probieren...



  • habe mein Programm erweitert:

    #include <iostream>
    #include <conio.h>
    #include <stdlib.h>
    #include <string>
    using namespace std;
    
    struct Verwaltung
    	{	string Name;
    		int Nummer;
    	};
    	Verwaltung *Personen;
    
    void Arbeiterauflisten(Verwaltung*,int);
    void Arbeiterneu(Verwaltung*,int);
    void Arbeiteraendern();
    void Arbeiterloeschen();
    
    int main()
    {
    	int n=1;
    	char Eingabe;
    
    	do
    	{	system("cls");
    		cout << "\tPersonalverwaltung";
    		cout << "\n\t~~~~~~~~~~~~~~~~~~\n\n";
    		cout << "1 --> Vorhandene Arbeiter ansehen";
    		cout << "\n2 --> Arbeiter hinzufuegen";
    		cout << "\n3 --> Arbeiter aendern";
    		cout << "\n4 --> Arbeiter loeschen";
    		cout << "\n\n0 --> Programm beenden";
    		cout << "\n\nIhre Eingabe:\t";
    
    		cin >> Eingabe;
    
    		switch (Eingabe)
    		{
    		case '1':
    			Arbeiterauflisten(Personen,n);
    			break;
    
    		case '2':
    			Arbeiterneu(Personen,n);
    			break;
    
    		case '3':
    			Arbeiteraendern();
    			break;
    
    		case '4':
    			Arbeiterloeschen();
    			break;
    		}
    	}
    	while (Eingabe != '0');
    
    	return 0;
    }
    
    void Arbeiterauflisten(Verwaltung *Pers,int v)
    {	system("cls");
    	cout << "\tIhre Arbeiter:";
    	cout << "\n\t~~~~~~~~~~~~~";
    	for (int x=0; x<v && Pers[x].Name.length()!=0; x++)
    	{	cout << "\n\nName, Person " << x << ":\t\t";
    		cout << Pers[x].Name ;
    		cout << "\nNummer, Person " << x << ":\t";
    		cout << Pers[x].Nummer ;
    
    		getch();
    	}
    }
    
    void Arbeiterneu(Verwaltung *Pers,int v)
    {	char Eing;
    	system("cls");
    	cout << "\tNeuer Arbeiter:";
    	cout << "\n\t~~~~~~~~~~~~~~";
    	do
    	{	*Pers=new Verwaltung[v];             // Hier kommt der Fehler
    		for (int x=0; x<v && Pers[x].Name.length()!=0; x++)
    		{	cout << "\nName, Person " << x << ":\t\t";
    			cin >> Pers[x].Name;
    			cout << "Nummer, Person " << x << ":\t";
    			cin >> Pers[x].Nummer;
    		}
    	cout << "Moechten Sie einen weiteren Arbeiter eingeben? (j/n)\n\n\t";
    
    	}
    	while (Eing=='j');
    
    	getch();
    }
    
    void Arbeiteraendern()
    {	system("cls");
    	cout << "\tIhre Arbeiter:";
    	cout << "\n\t~~~~~~~~~~~~~";
    	getch();
    }
    
    void Arbeiterloeschen()
    {	system("cls");
    	cout << "\tIhre Arbeiter:";
    	cout << "\n\t~~~~~~~~~~~~~";
    	getch();
    
    }
    

    und bekomme nun den Fehler:

    error C2679: Binärer Operator '=': Es konnte kein Operator gefunden werden, der einen rechtsseitigen Operator vom Typ 'Verwaltung *' akzeptiert (oder keine geeignete Konvertierung möglich)



  • 'Pers' ist ein Pointer auf ein Verwaltung-Objekt, also ist '*pers' ein Verwaltung-Objekt und dem kann kein Pointer zugewiesen werden. Du mußt direkt an 'Pers' zuweisen (und das als Referenz übergeben).

    (bzw wäre es besser, das Array nur einmal anzulegen - so würdest du es bei jedem 'neu'-Befehl wieder überschreiben)



  • CStoll schrieb:

    'Pers' ist ein Pointer auf ein Verwaltung-Objekt, also ist '*pers' ein Verwaltung-Objekt und dem kann kein Pointer zugewiesen werden. Du mußt direkt an 'Pers' zuweisen (und das als Referenz übergeben).)

    vor meiner Änderung ging es doch auch mit dem Stern, aber ok. Jedenfalls funzt es jetzt. danke

    CStoll schrieb:

    (bzw wäre es besser, das Array nur einmal anzulegen - so würdest du es bei jedem 'neu'-Befehl wieder überschreiben)

    da hast du recht, das hab ich übersehen...



  • ist bei dem Programm zwar nicht SO wichtig, aber: mach die globale Variable weg und in die main-Funktion rein. Du hast ja schon richtiger Weise deine Funktionen so gebaut, dass sie das Feld als Parameter verlangen. Globale Variable ist nicht nötig 🙂 Sollte man sich von Anfang an angewöhnen, die nicht groß zu benutzen.



  • welche variable meinst du? es ist doch keine globale da. oder meinst du die struktur? die muss aber global sein, da sonst der datentyp in der funktion unbekannt ist.



  • sarah1986 schrieb:

    oder meinst du die struktur? die muss aber global sein, da sonst der datentyp in der funktion unbekannt ist.

    Die Struktur selber kann schon global sein, muss, wie du sagtest, aber

    Verwaltung *Personen;
    

    ist global und sollte lieber in der main stehen.



  • Die Struktur kannst du im globalen namespace lassen.
    Ich meine das:

    Verwaltung *Personen;
    


  • achso.


Anmelden zum Antworten