Dynamische Arrays - Pointer



  • Hallo!

    Ich möchte mit calloc ein dynamisches Array erstellen und einen Zeiger darauf an ein Unterprogramm übergeben, wo die Daten wieder ausgelesen werden sollen, aber das Programm stürzt bei der Ausgabe ab mit der Meldung "Zugriffsverletzung beim Lesen an Position..."

    Bin noch nicht so erfahren im Umgang mit Zeigern und calloc..

    Suche jetzt schon die ganze Zeit den Fehler und weiß nicht weiter, hoffe hier kann mir jmd helfen! 😉

    Hier der Code:

    ...
    ...
    ...
    pArrAktPer =(ppperson_t)calloc(AnzDat,sizeof(pAktPer));
    
    // ppperson_t ist Zeiger auf Zeiger auf Struktur (per typedef),
    // AnzDaten die benötigten Datensätze
    // und pAktPer ist Zeiger auf Struktur
    
    	do{
    
    		printf("Datensatz %2d", i+1);
    		printf("\nFamilienname: ");  gets(fNam);
    
        if(strlen(fNam) == 0) break; 
    
        strcpy(Person.fNam, fNam);   
    
        printf("Vorname     : ");  gets(        Person.vNam);    
        printf("Geburt Tag  : ");  scanf("%u", &Person.gebDat.gdTag);  
        printf("Geburt Monat: ");  scanf("%u", &Person.gebDat.gdMonat);
        printf("Geburt Jahr : ");  scanf("%u", &Person.gebDat.gdJahr);
        printf("Personal-Nr.: ");  scanf("%u", &Person.identNr);   
        gets(fNam);                              
        pAktPer[i]  = Person; 
    
        i++; 
    
        printf("\n");    
    
      } while (i != AnzDat);
      strcpy(pAktPer[i].fNam, EMPTYTAG_S);
    
      return pAktPer;
    }
    
    //########################################
    //# 3. Datensätze im Bildschirm anzeigen #
    //########################################
    
    void WritePerToCrt(pperson_t pAktPer){
    
    	person_t Person;                
      int      i;                     
    
      printf("Folgende Personen wurden abgespeichert: \n\n");
      for( i = 0; pAktPer[i].fNam[0]!= EMPTYTAG_C; i++ ) {
        Person = *pAktPer;          
        printf("%5.5u  %-*s  %-*s  %2.2u.%2.2u.%u \n",
               Person.identNr, NAMLEN+1, Person.fNam, NAMLEN+1, Person.vNam,
               Person.gebDat.gdTag, Person.gebDat.gdMonat, Person.gebDat.gdJahr);
      } 
      printf("\n\n");
    
    }
    


  • Ich sehe in deinem Code nicht durch. Benutze entweder einen Debugger, der kann dir recht genau sagen wo der Fehler liegt, oder benutze printf um vor und nach dem Funktionsaufruf die Strukturen auszugeben und verschiebe die Ausgaben bis du irgendwann die Stelle findest ab der das nicht mehr funktioniert.

    Aber nur so ins Blaue geraten: Hast du vielleicht vergessen Speicher für die einzelnen Strukturen anzulegen? Nur weil du dir mit calloc Speicher für ppperson_t geholt hast heißt das nicht dass person_t Speicher hat.



  • Also erstmal: Du castest calloc() - das ist PFUI!

    Zweitens wirkt Dein Ansatz schizoid:
    Entweder Du reservierst genug Speicher für die bekannte Anzahl der Elemente(, dann kannste ja for gegen eine komkrete Var laufen lassen) oder mindestens eins mehr als die bekannte Anzahl der Elemente und kennzeichnest das letzte über Dein EMPTYTAG_C. Beides? Also, ich weiß nicht ...

    Irgendwo scheint da bei Dir der Hund begraben zu sein. Genauer kann ich das jetzt auch nicht sagen ...



  • ja, unser prof hat uns ziemlich viel vorgegeben, das sollen wir alles mit einbauen. wie die funktionen aufgerufen werden sollen ist auch vorgegeben.

    dazu sollen wir halt mit calloc dynamisch reservieren UND das schlußzeichen verwenden. das war die einzige lösung die mir dazu einfiel. wenn ich calloc nicht caste krieg ich nur fehler...bin aber über bessere lösungen sehr dankbar.

    das komische ist, wenn ich innerhalb der funktion die ausgabe mache, wo auch eingelesen wird, funktioniert es. schätze mal ich mache irgendeinen dummen anfängerfehler bei der zeigerübergabe.

    bitte nicht steinigen, bin noch total unerfahren 🙂 danke schonmal falls sich jmd die zeit nimmt.

    hier mal falls es was bringt das ganze prog.
    also das ist mal sein header:

    typedef unsigned int ui_t;        // Typname: unsigned int
      //
      typedef struct gd_e {             // Etikett: Struktur Geburtsdatum
                ui_t gdTag;
                ui_t gdMonat;
                ui_t gdJahr;
              } gd_t;                   // Typname: Struktur fuer ein Geburtsdatum
      //
      typedef struct person_e {         // Etikett: Struktur Person
                ui_t  identNr;
                nam_t fNam, vNam;
                gd_t  gebDat;
              } person_t;               // Typname: Struktur fuer eine Person
      //
      typedef person_t*  pperson_t;     // Typname: Zeiger auf Struktur
      //
      typedef pperson_t* ppperson_t;    // Typname: Zeiger auf Zeiger auf Struktur
    
    #endif
    

    Jetzt sollen wir selbst nen header schreiben, da hab ich bis jetzt das drin:

    //###########################################
    //# 2. Datensätze von der Tastatur einlesen #
    //###########################################
    
    pperson_t ReadFromKbd (void) {
    
    	char       fNam[21];
    	int        i=0;
    	int        AnzDat;
    	person_t   Person;									   			// Struktur
    	pperson_t  pAktPer    = &Person;               // Zeiger auf Struktur 0 bis AnzDat
    	ppperson_t pArrAktPer = &pAktPer;           // Zeiger auf ArrDatStr
    
    	printf("Projekt 1 - Crap Beta             T.Mueller\n"
    				 "*******************************************\n\n"
    				 "Eingabe von bis zu 10 Personendatensaetzen "
    				 "(Ende: leerer Familienname)\n\n"
    				 "Anzahl einzulesender Datensaetze: ");
    
    	scanf("%2d", &AnzDat); 
    	gets(fNam);
    	printf("\n");
    
    	if(AnzDat < MINPERANZ) AnzDat = MINPERANZ;
    	if(AnzDat > MAXPERANZ) AnzDat = MAXPERANZ;
    
    	pArrAktPer = (ppperson_t)calloc(AnzDat,sizeof(person_t));
    
    	do{
    
    		printf("Datensatz %2d", i+1);
    		printf("\nFamilienname: ");  gets(fNam);
    
        if(strlen(fNam) == 0) break; 
    
        strcpy(Person.fNam, fNam);   
    
        printf("Vorname     : ");  gets(        Person.vNam);    
        printf("Geburt Tag  : ");  scanf("%u", &Person.gebDat.gdTag);  
        printf("Geburt Monat: ");  scanf("%u", &Person.gebDat.gdMonat);
        printf("Geburt Jahr : ");  scanf("%u", &Person.gebDat.gdJahr);
        printf("Personal-Nr.: ");  scanf("%u", &Person.identNr);   
        gets(fNam);                              
        pAktPer[i]  = Person; 
    
        i++; 
    
    		printf("\n");    
    
    	} while (i != AnzDat);
    	strcpy(pAktPer[i].fNam, EMPTYTAG_S);
    
    	return pAktPer;
    }
    
    //########################################
    //# 3. Datensätze im Bildschirm anzeigen #
    //########################################
    
    void WritePerToCrt(pperson_t pAktPer){
    
    	person_t Person; 
    	char buffer[81];               
      int      i;                     
    
      printf("Folgende Personen wurden abgespeichert: \n\n");
      for( i = 0; pAktPer[i].fNam[0]!= EMPTYTAG_C; i++ ) {
        Person = pAktPer[i];          
        printf("%5.5u  %-*s  %-*s  %2.2u.%2.2u.%u \n",
               Person.identNr, NAMLEN+1, Person.fNam, NAMLEN+1, Person.vNam,
               Person.gebDat.gdTag, Person.gebDat.gdMonat, Person.gebDat.gdJahr);
    		if(pAktPer[i].fNam[0] == EMPTYTAG_C) break;
      } 
      printf("\n\n");
    
    	printf("Eingabe Dateiname ohne Erweiterung [ret=perlis]: ");
    	gets(buffer);
    
    //#########################################
    //# 6. Free-Funktion - Speicher freigeben #
    //#########################################
    
    void FreeDynMem(ppperson_t pArrAktPer, int AnzDat){
    	free(pArrAktPer);
    }
    

    und die main:

    int main(void){
    
    int AnzDat;
    ppperson_t pArrAktPer;
    pperson_t pAktPer;
    
    	ReadFromKbd();
    	WritePerToCrt(pAktPer);
    	FreeDynMem(pArrAktPer, AnzDat);
    return 0;
    }
    


  • Schau mal.

    pArrAktPer = (ppperson_t)calloc(AnzDat,sizeof(person_t));
    

    enthält zwei Unschönheiten: In C++ mußt Du casten, wahrscheinlich compilierst Du eine cpp- Datei. Benenne sie so um, daß die Endung .C lautet oder schau sonst zu, wie Du den Compiler dazu bringst, C zu compilieren. Wenn das ohne cast nicht klappt, mußt Du zur Strafe ins C++- Forum 😉
    Zweitens ist das sizeof besser am konkreten Objekt festzumachen, besser also:

    pArrAktPer = calloc(AnzDat,sizeof(Person));
    

    Beides nachzulesen in den ANSI- C- FAQs

    Dann schau mal zu Zeile 53/54: Da weist Du bei i == AnzDat die komische Stopmarke zu, aber wohin? Es gibt nur 0 ... AnzDat-1 Elemente (als Index besehen). Das ist schonmal nicht richtig.

    Was Du mit den Strings machst, kommt mir auf den ersten Blick etwas seltsam vor, mach' aber erstmal das Offensichtliche klar, dann sehhen wir weiter ...



  • #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define MAX_NAME_LENGTH 50
    
    typedef unsigned int ui_t;
    typedef char nam_t;
    
    typedef struct gd_e {
    	ui_t gdTag;
    	ui_t gdMonat;
    	ui_t gdJahr;
    }gd_t;
    
    typedef struct person_e {
    	ui_t  identNr;
    	nam_t fNam[MAX_NAME_LENGTH], vNam[MAX_NAME_LENGTH];
    	gd_t  gebDat;
    }person_t;
    
    //###########################################
    //# 1. helper fn                            #
    //###########################################
    
    void clearStdIn(){
    	char buffer[1024];
    	fgets(buffer,1024,stdin);
    }
    
    void scanfEx(char *str,void *type){
    	scanf(str,type);
    	clearStdIn();
    }
    void fgetsEx(char *ret,int len,FILE *fp){
    	fgets(ret,len,fp);
    	ret[strlen(ret)-1]='\0';//remove '\n'
    }
    //###########################################
    //# 2. Datensätze von der Tastatur einlesen #
    //###########################################
    
    person_t **ReadFromKbd (void) {
    	int 		i = 0;
    	int       AnzDat=0;
    	person_t  **Person;
    
    	printf(
    		"Projekt 1 - Crap Beta             T.Mueller | noobLolo\n"
    		"*******************************************\n\n"
    		"Eingabe von bis zu 10 Personendatensaetzen "
    		"(Ende: leerer Familienname)\n\n"
    		"Anzahl einzulesender Datensaetze: "
    	);
    
    	scanfEx("%2d", &AnzDat);
    	printf("\n");
    
    	if(AnzDat < 1)
    		return NULL;
    	//gibt es ein max wenn ja warum?
    	//if(AnzDat > MAXPERANZ) AnzDat = MAXPERANZ;
    
    	//array
    	Person = calloc(AnzDat+1,sizeof(person_t*));
    	if(Person==NULL)
    		return NULL;
    
    	i=AnzDat;
    	//pArrAktPer[i]=NULL; //unser neuer end wert implizit :)
    
    	while(i--){
    		//ein datensatz fuer das array
    		Person[i] = calloc(1,sizeof(person_t));
    		if(Person[i]==NULL)
    			return NULL;
    	}
    
    	for(i=0;i<AnzDat;i++){
    		printf("Datensatz %2d\n", i+1);
    		printf("Familienname: ");  fgetsEx(Person[i]->fNam,MAX_NAME_LENGTH-1,stdin);
    		printf("Vorname     : ");  fgetsEx(Person[i]->vNam,MAX_NAME_LENGTH-1,stdin);
    		printf("Geburt Tag  : ");  scanfEx("%u", &Person[i]->gebDat.gdTag);
    		printf("Geburt Monat: ");  scanfEx("%u", &Person[i]->gebDat.gdMonat);
    		printf("Geburt Jahr : ");  scanfEx("%u", &Person[i]->gebDat.gdJahr);
    		printf("Personal-Nr.: ");  scanfEx("%u", &Person[i]->identNr);
    	}
    
    	return Person;
    }
    
    //########################################
    //# 3. Datensätze im Bildschirm anzeigen #
    //########################################
    
    void WritePerToCrt(person_t **Person){
    	int l=0;
    	printf("Folgende Personen wurden abgespeichert: \n\n");
    
    	while(Person[l]){
    		printf("%5.5u  %-*s  %-*s  %2.2u.%2.2u.%4.4u \n",
    			Person[l]->identNr
    			, MAX_NAME_LENGTH+1, Person[l]->fNam
    			, MAX_NAME_LENGTH+1, Person[l]->vNam
    			, Person[l]->gebDat.gdTag
    			, Person[l]->gebDat.gdMonat
    			, Person[l]->gebDat.gdJahr
    		);
    		l++;
    	}
    
    	printf("\n\n");
    }
    
    //#########################################
    //# 4. Datensätze in datei speichern      #
    //#########################################
    
    //#########################################
    //# 5. Datensätze aus datei lesen         #
    //#########################################
    
    //#########################################
    //# 6. Free-Funktion - Speicher freigeben #
    //#########################################
    void FreeDynMem(person_t **Person){
    	int l=0;
    	while(Person[l])
    		free(Person[l++]);
    	free(Person);
    }
    
    int main(void){
    	person_t **Person;
    
    	Person = ReadFromKbd();
    	if(Person==NULL)
    		return 1;
    
    	WritePerToCrt(Person);
    	FreeDynMem(Person);
    	return 0;
    }
    

    wie immer ist sicher auch das ein bischen buggy 😉

    lg lolo



  • pAktPer[i].fNam[0]!= EMPTYTAG_C
    

    😮

    sowas ist ungünstig, denn wer weiß schon was es so für namen gibt, stell dir mal vor du denkst dir da nen namen aus den es deiner meinung nach nicht gibt und dann kommt einer daher und gibt das ein...

    als ich meinen führerschein gemacht hab hat mein fahrlehrer immer gesagt man muß mit der dummheit der anderen rechnen,

    beim programmieren mußt du immer mit der dummheit des users rechnen, der immer das eingibt woran du nicht gedacht hast 😉

    pointercrash() schrieb:

    Wenn das ohne cast nicht klappt, mußt Du zur Strafe ins C++- Forum 😉

    hab mich ja weggeschossen als ich das gelesen hab *rofl*



  • #define EMPTYTAG_C 0
    

    🙂



  • x0r schrieb:

    #define EMPTYTAG_C 0
    

    🙂

    noobLolo schrieb:

    beim programmieren mußt du immer mit der dummheit des users rechnen, der immer das eingibt woran du nicht gedacht hast 😉

    und mit seiner eigenen 😃



  • genau, ist ne vs c++ consolenanwendung. müssen wir in der uni so benutzen, soll ich nen mod anschreiben damit der thread ins c++ verschoben wird? 🙂 dachte hier wär das am besten aufgehoben.

    Zeile53 ist jetzt

    } while (i < AnzDat);
    	strcpy(pAktPer[i+1].fNam, EMPTYTAG_S);
    

    und das sizeof hab ich auch geändert. dachte ich sprech lieber direkt mit person_t die struktur an statt über eine variable. aber ich vermute ich verstehe irgendwas an calloc oder an zeigern nicht. füg ich die ausgabe direkt unter der schleife ein funktioniert alles einwandfrei 😕 dieses indirekte mit zeigern auf zeiger auf strukturen verwirrt mich noch total...

    hab das calloc mal in

    pArrAktPer =(pperson_t)calloc(AnzDat+1,sizeof(Person));
    

    geändert, +1 weil ja das schlußzeichen noch gesetzt werden soll.
    ich bin etwas irritiert was genau jetzt der linke wert darstellt und wie ich damit umgehen soll.

    die ausgabe-funktion erwartet einen einfachen zeiger auf die strukturen. pArrAktPer ist doch jetzt aber ein zeiger auf einen zeiger im reservierten speicher, der auf die strukturen personen*Anzahl Datensätze zeigt... oder ist das falsch?

    in der schleife möchte ich mit

    pAktPer[i] = Person;
    

    jeweils ein datensatz/eine struktur hinzufügen, bin mir nicht sicher ob das so 100% richtig ist, aber es geht wie gesagt merkwürdigerweise wenn ich die ausgabe gleich danach mache.

    wenn ich aber versuche über

    return pAktPer;
    

    den zeiger zu übergeben, stürzt das programm ab. Bei einigen rumprobier-versuchen mit calloc klappte noch das printf("Folgende Personen usw"), aber dann war ab der for auch schluss...

    //herrje bin ich langsam...



  • habs mal bischen geändert

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define MAX_NAME_LENGTH 50
    
    typedef unsigned int ui_t;
    typedef char nam_t;
    
    typedef struct gd_e {
    	ui_t gdTag;
    	ui_t gdMonat;
    	ui_t gdJahr;
    }gd_t;
    
    typedef struct person_e {         // Etikett: Struktur Person
    	ui_t  identNr;
    	nam_t fNam[MAX_NAME_LENGTH], vNam[MAX_NAME_LENGTH];
    	gd_t  gebDat;
    }person_t;               // Typname: Struktur fuer eine Person
    
    //###########################################
    //# 0. helper fn                            #
    //###########################################
    
    void clearStdIn(){
    	char buffer[1024];
    	fgets(buffer,1024,stdin);
    }
    
    void scanfEx(char *str,void *type){
    	scanf(str,type);
    	clearStdIn();
    }
    void fgetsEx(char *ret,int len,FILE *fp){
    	fgets(ret,len,fp);
    	ret[strlen(ret)-1]='\0';//remove '\n'
    }
    //###########################################
    //# 2. Datensätze von der Tastatur einlesen #
    //###########################################
    
    person_t *ReadFromKbd (void) {
    	int 		i = 0;
    	int       AnzDat=0;
    	person_t  *Person;
    
    	printf(
    		"Projekt 1 - Crap Beta             T.Mueller | noobLolo\n"
    		"*******************************************\n\n"
    		"Eingabe von bis zu 10 Personendatensaetzen "
    		"(Ende: leerer Familienname)\n\n"
    		"Anzahl einzulesender Datensaetze: "
    	);
    
    	scanfEx("%2d", &AnzDat);
    	printf("\n");
    
    	if(AnzDat < 1)
    		return NULL;
    	//gibt es ein max wenn ja warum?
    	//if(AnzDat > MAXPERANZ) AnzDat = MAXPERANZ;
    
    	//array
    	Person = calloc(AnzDat+1,sizeof(person_t));
    	if(Person==NULL)
    		return NULL;
    
    	for(i=0;i<AnzDat;i++){
    		printf("Datensatz %2d\n", i+1);
    		printf("Familienname: ");  fgetsEx(Person[i].fNam,MAX_NAME_LENGTH-1,stdin);
    		printf("Vorname     : ");  fgetsEx(Person[i].vNam,MAX_NAME_LENGTH-1,stdin);
    		printf("Geburt Tag  : ");  scanfEx("%u", &Person[i].gebDat.gdTag);
    		printf("Geburt Monat: ");  scanfEx("%u", &Person[i].gebDat.gdMonat);
    		printf("Geburt Jahr : ");  scanfEx("%u", &Person[i].gebDat.gdJahr);
    		printf("Personal-Nr.: ");  scanfEx("%u", &Person[i].identNr);
    	}
    
    	return Person;
    }
    
    //########################################
    //# 3. Datensätze im Bildschirm anzeigen #
    //########################################
    
    void WritePerToCrt(person_t *Person){
    	int l=0;
    	printf("Folgende Personen wurden abgespeichert: \n\n");
    
    	while(Person[l].fNam[0]!=0){
    		printf("%5.5u  %-*s  %-*s  %2.2u.%2.2u.%4.4u \n",
    			Person[l].identNr
    			, MAX_NAME_LENGTH+1, Person[l].fNam
    			, MAX_NAME_LENGTH+1, Person[l].vNam
    			, Person[l].gebDat.gdTag
    			, Person[l].gebDat.gdMonat
    			, Person[l].gebDat.gdJahr
    		);
    		l++;
    	}
    
    	printf("\n\n");
    }
    
    //#########################################
    //# 4. Datensätze in datei speichern      #
    //#########################################
      /*void WritePerToFile(pperson_t pAktPer){
          printf("Eingabe Dateiname ohne Erweiterung [ret=perlis]: ");
          gets(buffer);
      }*/
    
    //#########################################
    //# 6. Free-Funktion - Speicher freigeben #
    //#########################################
    void FreeDynMem(person_t *Person){
    	free(Person);
    }
    
    int main(void){
    	person_t *Person;
    
    	Person = ReadFromKbd();
    	if(Person==NULL)
    		return 1;
    
    	WritePerToCrt(Person);
    	FreeDynMem(Person);
    	return 0;
    }
    

    scheint so als sollte ich mir das mit den arrays nochmal durch den kopf gehen lassen 😃



  • wie immer ist sicher auch das ein bischen buggy 😉

    lg lolo[/quote]

    wow, respekt&thx!

    aber bei beiden calloc (Zeile 66 & 75) selbes problem wie vorher:

    Fehler	2	error C2440: '=': 'void *' kann nicht in 'person_t **' konvertiert werden
    

    😕

    // schon wieder gelat0rt -.-

    //2 ok, mitm cast gehts. riesen danke, du hast mir ech geholfen!



  • noobLolo schrieb:

    x0r schrieb:

    #define EMPTYTAG_C 0
    

    🙂

    noobLolo schrieb:

    beim programmieren mußt du immer mit der dummheit des users rechnen, der immer das eingibt woran du nicht gedacht hast 😉

    und mit seiner eigenen 😃

    Was ist an dem define so dumm? Vielleicht benutzt der Prof noch Magnetbänder zur Speicherung der Datensätze. 👍



  • noobLolo schrieb:

    und mit seiner eigenen 😃

    das bezog sich darauf das mir diese möglichkeit nicht eingefallen ist 😞


Anmelden zum Antworten