Problem bei der Ausgabe (Dynamische Speicherverwaltung)



  • sarah1986 schrieb:

    aber warum ist das bei dem 1. was ich hingeschrieben hab mal mit stern, mal ohne. das waren beides arrays. und beides funzt, bei dem einen prog mit, bei dem anderen ohne stern.

    Es kommt drauf an, was in dem Array drinne ist.

    Verwaltung *Pers = new Verwaltung[v];
    

    Hier hast du ein Feld von Objekten. Wenn du den Zeiger derefernezierst(ob mit * und . oder mit [] ist egal) befindest du dich jetzt quasi im Objekt.

    Zurück zum statischen:

    Verwaltung *Pers[100];
    

    Das ist ein Feld von Zeigern, oben drüber warns Objekte, jetzt sind es Zeiger ⚠ ⚠
    du kannst jetzt jedem Zeiger ein Objekt zuweisen

    pers[0] = new Verwaltung; //Achtung, EIN Objekt hier, kein Feld
    pers[1] = new Verwaltung; //Achtung, EIN Objekt hier, kein Feld
    usw.
    

    Wenn du jetzt pers derefernzierst, wo bist du dann? GENAU, wieder bei einem Zeiger, wir haben ja au schließlich ein Zeigerfeld.
    Was macht man mit Zeigern? Richtig, bei bedarf dereferenzieren

    (*pers[0]).name;
    

    Jetzt hast du einen Zeiger auf einen Zeiger. Bei 2 Zeigern. muss man auch 2 mal dereferenzieren. Das erste mal wird mit [] dererenziert, siehe POst oben, das zweite mal dann direkt mit dem *

    versuch das mal in Ruhe nachzuvollziehen, auch wenns jetzt beim Ersten lesen verwirrend ist.
    Du musst halt immer schauen, was du hast: Zeiger oder Objekt



  • sarah1986 schrieb:

    aber warum ist das bei dem 1. was ich hingeschrieben hab mal mit stern, mal ohne. das waren beides arrays. und beides funzt, bei dem einen prog mit, bei dem anderen ohne stern.

    Man kann auch Pointer auf Pointer anlegen, deshalb "ging" das:

    //Erstellen:
    int zeilen=5,spalten=10;
    Verwaltung **Pers;  //Ein Pointer auf weitere Pointer
    Pers = new Verwaltung*[zeilen];  //Erstmal die Zeilen holen
    
    for (int i=0;i<zeilen;++i)
      *(Pers+i) = new Verwaltung[spalten]; // Spalten anlegen
    
    //Löschen:
    for (size_t i=0;i<zeilen;++i)
      delete [] *(Pers+i);  //Spalten freigeben
    
    delete [] Pers;  //Zeilen freigeben
    Pers = 0;
    

    EDIT:

    wo liegt denn bei meiner prog der fehler, dass ich diesen blöden failure bekomme? ich hab, meiner meinung nach, alles richtig.

    Poste mal den aktuellen Code.



  • #include <iostream>
    #include <conio.h>
    #include <stdlib.h>
    #include <string>
    using namespace std;
    
    struct Verwaltung
    	{	string Name;
    		int Nummer;
    	};
    
    void Arbeiterauflisten(Verwaltung*,int);
    void Arbeiterneu(Verwaltung*,int);
    void Arbeiteraendern();
    void Arbeiterloeschen();
    
    int main()
    {
    	int n=1;
    	char Eingabe;
    	Verwaltung *Personen;
    
    	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 << x << " -->\t";
    		cout << "\tName:\t";
    		cout << Pers[x].Name ;
    		cout << "\n\t\tNummer:\t";
    		cout << Pers[x].Nummer ;
    
    		getch();
    	}
    }
    
    void Arbeiterneu(Verwaltung *Pers,int v)
    {	char Eing=' ';
    	system("cls");
    	cout << "\tNeuer Arbeiter:";
    	cout << "\n\t~~~~~~~~~~~~~~";
    	Pers=new Verwaltung[v];
    	do
    	{	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();
    }
    


  • WEnn ich raten soll: du arbeitest im Debugmodus und hast irgendwo einen Speicherzugriff auf ein nicht existierendes Objekt

    for (int x=0; x<v && Pers[x].Name.length()!=0; x++)
    

    Das ist aus der Arbeiterneu. Das Pers[x].Name.length(), was soll das dort?



  • Pellaeon schrieb:

    WEnn ich raten soll: du arbeitest im Debugmodus und hast irgendwo einen Speicherzugriff auf ein nicht existierendes Objekt

    for (int x=0; x<v && Pers[x].Name.length()!=0; x++)
    

    Das ist aus der Arbeiterneu. Das Pers[x].Name.length(), was soll das dort?

    ich möchte ausschließen, dass die daten mit "leerem" namen ausgegeben werden.
    ich weiß, dass dies so vermutlich net möglich ist, weil ich ja das selbe x wieder verwenden möchte. gibt es denn keine andere möglichkeit, außer das alles wieder in ne if-anweisung zu stecken?



  • mach das mal beim Anlegen der Personen raus



  • habe ich. trotzdem kommt der fehler weiterhin.



  • an welcher Stelle passiert er denn jetzt?



  • wenn ich im menu, 1 oder 2 auswähle, bei beidem. 3 und 4 funzt, wie es soll.
    also genau:
    bei

    case 1:
    Arbeiterauflisten(Personen,n);              // <--
    
    case 2:
    Arbeiterneu(Personen,n);                   // <--
    

    in den beiden zeilen, jenachdem was ich halt aufrufe

    EDIT: hab die falsche funktion angegeben...



  • Du benötigst auch noch ein new, um dir vernünftigen Speicherplatz anzulegen (am besten direkt bei der Deklaration der Variable Personen):

    Verwaltung* Personen=new Verwaltung[n];
    


  • das habe ich ja in der funktion. muss ich das schon im main machen?



  • case 1:
    Arbeiterauflisten(Personen,n);
    

    Das crasht, weil du auf Speicher zugreifen willst, den du garnicht reserviert hast. Wenn du es als erstes aufrust, gibt es ja noch keine Personen, das weis die Funktion aber nicht und greift auf den Zeiger zu. Doch der Zeiger enthält irgendwas, irgendwas zufälliges, ist also nicht initialisiert.

    case 2:
    Arbeiterneu(Personen,n);
    

    Schau dir mal die Funktion an, du übergibst einen Zeiger. Der Zeiger an sich in der Funktion ist eine Kopie, also die Adresse, welche in "Personen" steht, wird nach "Pers" kopiert.

    Nun machst du in der Funktion ein new. Dabei wird Speicher reserviert, und die Adresse des neuen Speicher zurück gegeben. Diese wird in Pers gespeichert. Dann wird damit gearbeitet. Die Adresse wird aber nie zurück gegeben, d.h "Personen" erfährt nie, wo das neu erstellte Feld steht. Du müsstest also den Parameter "Pers" bei Arbeiterneu wemnachen(nicht vergessen dafür eine lokale Variable in der Funktion anzulegen) und den Zeiger dann als Rückgabewert der Funktioen machen.

    Warum das dort crasht seh ich jetz nicht. Da musst du mal mit dem Debugger reingehen in die Funktione und schauen, bei welchem Befehl genau der Fehler dann auftritt

    Verwaltung* Arbeiterneu(int v)
    {    
        char Eing=' ';
        system("cls");
        cout << "\tNeuer Arbeiter:";
        cout << "\n\t~~~~~~~~~~~~~~";
        Verwaltung* Pers = new Verwaltung[v];
        do
        {    for (int x=0;x < v;++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();
    
        return Pers;
    }
    

    Es ist auf gefährlich einfach zu sagen das Feld ist v groß, aber der Nutzer darf trotzdem noch entscheiden, wieviel rein kann.



  • der benutzer gibt das ja nicht vor, das mache ich im programm



  • was für ne variable soll ich in der funktion anlegen, ich brauch doch da garkeine mehr, wofür soll ich die nehmen?



  • sarah1986 schrieb:

    der benutzer gibt das ja nicht vor, das mache ich im programm

    In deiner Schleife wird der Nutzer gefragt, ob er weiter machen will oder nicht.



  • sarah1986 schrieb:

    was für ne variable soll ich in der funktion anlegen, ich brauch doch da garkeine mehr, wofür soll ich die nehmen?

    Der Parameter ist eine lokale Kopie des übergebenen Wertes - d.h. wenn du dort etwas mit new zuweist, ändert sich der Wert im Hauptprogramm überhaupt nicht. Deshalb solltest du aus der Anlegen-Funktion die mit new erhaltene Adresse nach außen zurückgeben (entweder mit return oder indem du den Parameter als "Verwaltung*& Pers" deklarierst).

    Ein weiterer logischer Fehler ist, daß du bei jedem Aufruf von Arbeiterneu ein neues Array anlegst und das alte irgendwo im Speicher vergisst.

    PS: Und ich bin immer noch der Meinung, daß du lieber einen STL-Container verwenden solltest statt "dynamisch" mit Arrays rumzuschießen.



  • das prob ist, dass wir das in der schule gemacht haben, und ich das irgendwie können muss.



  • Hm du solltest echt schauen, dass du jemanden in deiner Klasse findest, der dir das erklärt. Am besten mit Bildchen und aufmalen usw. Du hast da noch ein Verständnisproblem, und langsam gehen mir auch die Ideen aus, wie ich das noch anschaulich schreiben soll^^ Is nicht böse gemeint.



  • no prob. aber ich bin so schon sehr froh und sehr dankbar, dass ihr euch alle mühe gegeben habt, um mir zu helfen. ist wirklihc super lieb!!!



  • Heute hat ein Arbeitskollege mir gesagt, dass ich das Prog im Grunde total falsch programmiert habe, da ich zwar ein Pointer-Array angelegt habe, aber dies nicht wirklich integriert habe.

    Ich habe es jetzt so verändert, dass es passen müsste:

    #include <iostream>
    #include <conio.h>
    #include <stdlib.h>
    #include <string>
    using namespace std;
    
    struct Verwaltung
    	{	string Name;
    		int Nummer;
    	};
    
    void Arbeiterauflisten(Verwaltung*,int);
    int Arbeiterneu(Verwaltung*,int);
    void Arbeiteraendern();
    void Arbeiterloeschen();
    
    int main()
    {
    	int Anzahl=0;
    	const int n=100;
    	char Eingabe;
    	Verwaltung *Personen[n];
    
    	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,Anzahl);
    			break;
    
    		case '2':
    			Anzahl=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~~~~~~~~~~~~~";
    	cout << "\n\nSie haben folgende Datensaetze eingegeben:\n";
    	for (int x=0; x<v; x++)
    	{	cout << "\n\nName, Person " << x << ":\t\t";
    		cout << Pers[x]->Name;
    		cout << "\nNummer, Person " << x << ":\t";
    		cout << Pers[x]->Nummer;
    	}
    }
    
    int Arbeiterneu(Verwaltung *Pers[],int v)
    {	char Eing=' ';
    	system("cls");
    	cout << "\tNeuer Arbeiter:";
    	cout << "\n\t~~~~~~~~~~~~~~";
    	int x=0;
    
    	do 
    	{	
    		Pers[x]=new Verwaltung;
    		cout << "\nName, Person " << x << ":\t\t";
    		cin >> Pers[x]->Name;					//alternativ: (*Personen[x]).Name
    		cout << "Nummer, Person " << x << ":\t";
    		cin >> Pers[x]->Nummer;
    		v++;
    		x++;
    		cout << "Moechten Sie einen weiteren Datensatz einlesen?";
    		cin >> Eing;
    	}
    	while (x<v && Eing=='j');
    	getch();
    	return v;
    }
    
    void Arbeiteraendern()
    {	system("cls");
    	cout << "\tIhre Arbeiter:";
    	cout << "\n\t~~~~~~~~~~~~~~";
    
    	/*for (int x=0; x<AnzSaetze; x++)
    	{	cout << "\n\nName, Person " << x << ":\t\t";
    		cout << Personen[x]->Name;
    		cout << "\nNummer, Person " << x << ":\t";
    		cout << Personen[x]->Nummer;
    	}*/
    
    	getch();
    }
    
    void Arbeiterloeschen()
    {	system("cls");
    	cout << "\tIhre Arbeiter:";
    	cout << "\n\t~~~~~~~~~~~~~~";
    
    	/*for (int x=0; x<AnzSaetze; x++)
    	{	cout << "\n\nName, Person " << x << ":\t\t";
    		cout << Personen[x]->Name;
    		cout << "\nNummer, Person " << x << ":\t";
    		cout << Personen[x]->Nummer;
    	}*/
    
    	//delete Personen[x];
    	//Personen[x]=NULL;
    	getch();
    
    	/*Personen=new Verwaltung[n];
    	for (int x=0; x<n; x++)
    	{	cout << "\nName, Person " << x << ":\t\t";
    		cin >> Personen[x].Name;
    		cout << "Nummer, Person " << x << ":\t";
    		cin >> Personen[x].Nummer ;
    	}
    
    	delete[] Personen;*/
    
    }
    

    jetzt bekomme ich zwei Fehlermeldungen, mit denen ich nichts anfangen kann. Ich hoffe, ihr könnt mir helfen.

    error C2664: 'Arbeiterauflisten': Konvertierung des Parameters 1 von 'Verwaltung *[100]' in 'Verwaltung *' nicht möglich
    Die Typen, auf die verwiesen wird, sind nicht verknüpft; die Konvertierung erfordert einen reinterpret_cast-Operator oder eine Typumwandlung im C- oder Funktionsformat.

    error C2664: 'Arbeiterneu': Konvertierung des Parameters 1 von 'Verwaltung *[100]' in 'Verwaltung *' nicht möglich
    Die Typen, auf die verwiesen wird, sind nicht verknüpft; die Konvertierung erfordert einen reinterpret_cast-Operator oder eine Typumwandlung im C- oder Funktionsformat.

    Mit Typumwandlung habe ich noch nichts gemacht, und in einem Beispiel ist es so verwirklicht, wie ich es auch hab. (Beim Funktionsaufruf nur der Name des Pointer-Arrays übergeben, und in der Funktion einen Namen dafür vergeben mit [] aber ohne Inhalt, und mit Stern davor, eben wie bei mir)


Anmelden zum Antworten