Zeiger auf Struktur weiterschalten; malloc(); realloc();



  • Hallo zusammen,

    ich studiere Informatik (2.Semester) und scheitere an folgenden Problem:

    Wie kann man einen Zeiger, der auf einen Struktur zeigt, weiterschalten um einen neuen Eintrag in die "Datenbank" zu ermöglichen?

    Hier der C-Code:

    #include "header_malloc.h"
    #define HEAP_Faktor 5
    
    typedef struct 
    {
    	char Geräte_Beschreibung[4000];
    	long int Geräte_Nummer;
    	int Stückzahl;
    }Liste;
    
    void main()
    {
    Kopf(); 
    
    Liste *buffer, *pp;
    int max,nummer=1;
    char Geräte_Beschreibung[4000];
    printf("%31s  = %d\n\n","<HEAP_Faktor ",HEAP_Faktor); 
    
    max=sizeof(Liste);
    buffer=(Liste*) malloc(HEAP_Faktor*max); 
    if(buffer==NULL)
    {
    	printf("%51s\n","malloc<>-Meldung: Nicht gen\x81gend HEAP vorhanden!"),free(buffer);exit(1); 
    }
    
    printf("%34s = %p\n","**** HEAP-Adresse f\x81r 1. Ger\x84t",buffer); 
    printf("%24s%s =%12d Bytes","**** HEAP-Gesamtgr\x94\xE1","e",_msize(buffer)); 
    
    do
    {
    	printf("\n\n %d. Ger\x84t",nummer);
    	if(nummer>1&&_msize(buffer)-(nummer-1)*max==0)	//Start bei nummer=0
    	{
    		buffer=(Liste *) realloc(buffer,_msize(buffer)+max*HEAP_Faktor);	
    		printf("%s%p"," <...HEAP wurde verschoben nach Adr ",buffer); 
    		printf("\n%34s%s%6d Bytes","...neue HEAP-Gesamtgr\x94\xE1","e     =",_msize(buffer)); 
    		printf("\n%41s%6d Bytes\n","...noch freier HEAP-Speicher =",_msize(buffer)-((nummer-1)*max)); 
    
    	}
    	printf("\n%33s"," - Bezeichung <Ende mit \"0\">: "); 
    	scanf_s("%18s",&Geräte_Beschreibung,4000); 
    	fflush(stdin);
    	if(Geräte_Beschreibung[0]=='0') break;
    	else
    	{
    		strcpy(buffer->Geräte_Beschreibung,Geräte_Beschreibung); 
    		printf("%21s","- Ger\x84te_Nummer: "); 
    		scanf("%li",&buffer->Geräte_Nummer);		
    		fflush(stdin); 
    		printf("%14s","- Bedarf: ");				
    		scanf("%d",&buffer->Stckzahl);
    		fflush(stdin);
    		pp=buffer;
    		buffer++;//Fehlermeldung! Wie könnte man dann den Zeiger weiterschalten um weitere Einträge abzuspeichern?
    		nummer++;
    		printf("%37s%d Bytes","...freier HEAP_Speicher = ",_msize(buffer)-((nummer-1)*max)); 	
    
    	}
    
    }while(1); 
    
    printf("\n\n Einkaufliste:");
    printf("\n =============");
    printf("\n\n Pos. Ger\x84tebezeichung Nummer Bedarf");
    printf("\n -------------------------------------");
    for(int i=1; i<nummer;i++)
    {
    
    	printf("\n%3d%19s%7li%5i",i,(--buffer)->Geräte_Beschreibung,(--buffer)->Geräte_Nummer,(--buffer)->Stückzahl);
    
    }
    printf("\n\n-----------------------------------------------------------------------\n");
    }
    

    mfg Tom



  • hi there
    hab den code überflogen, folgendes fällt auf:
    du machst zu oft:

    buffer++;
    

    mach das, nachdem die eingaben aller structmember abgeschlossen sind.



  • Aber genau das habe ich doch gemacht.. oder an welcher Stelle würden sie buffer++; schreiben?


  • Mod

    printf("\n%3d%19s%7li%5i",i,(--buffer)->Geraete_Beschreibung,(--buffer)->Geraete_Nummer,(--buffer)->Stueckzahl);
    

    Argh! Welchen Wert hat buffer deiner Meinung nach hinterher?

    Weiterhin gehörst du wohl zu der Fraktion, die C mit einem C++-Compiler übersetzen. Tu das nicht!

    buffer=(Liste*) malloc(HEAP_Faktor*max);  // Wozu das (Liste*) ?
    
    // ...
    
    buffer++;  // Argh! Wie kommen wir nun jemals wieder an den Wert den wir vom malloc bekommen haben?
    

    Für mehr kann ich dir nicht helfen, da die Portierung dieses hochgradig unportablem Codes mir zu viel Arbeit wäre. Hättest du keine Umlaute im Code benutzt, alle nötigen Header eingebunden und keine unnötigen Windows-spezifischen Sachen benutzt, sähe das anders aus.



  • Sry. das uns genau so das Programmieren gelernt wird...

    printf("\n%3d%19s%7li%5i",i,(--buffer)->Geraete_Beschreibung,(--buffer)->Geraete_Nummer,(--buffer)->Stueckzahl);

    //Ich hätte halt gedacht das durch malloc(); ein gwisser Speicherplatz im "Heat" frei geräumt wird, ich diesen dann mit Struktur-Sätze fülle, wobei buffer immer auf den aktuellsten "Satz" zeigt. Die Ausgabe wollte ich dann über den Zeiger buffer durch (--buffer) ermöglichen.
    Wie kann man den Zeiger sonst auf den nächsten "Satz" umleiten?

    Die Umlaute sind von unserem Prof. so verlangt.
    Welche Header hätte ich den noch einbinden sollen?

    mfg



  • ThomasWa. schrieb:

    Sry. das uns genau so das Programmieren gelernt wird...

    ... gelehrt wird ...
    Ein Grundlagen-Deutsch Kurs wäre wohl auch zu empfehlen.
    Welchen Compiler setzt du ein?
    Hast du dir schon mal dessen Warnungen abgeschaut?
    Nein, hast du nicht, sonst würdest du nicht fragen.
    Der Compiler ist die erste und beste Kontrollinstanz für deinen Code.
    Der kennt sich besser mit C aus, als du und dein Professor zusammen es jemals könnten.



  • ThomasWa. schrieb:

    Sry. das uns genau so das Programmieren gelernt wird...

    printf("\n%3d%19s%7li%5i",i,(--buffer)->Geraete_Beschreibung,(--buffer)->Geraete_Nummer,(--buffer)->Stueckzahl);

    //Ich hätte halt gedacht das durch malloc(); ein gwisser Speicherplatz im "Heat" frei geräumt wird, ich diesen dann mit Struktur-Sätze fülle, wobei buffer immer auf den aktuellsten "Satz" zeigt. Die Ausgabe wollte ich dann über den Zeiger buffer durch (--buffer) ermöglichen.

    --buffer verändert die Variable buffer , sodass der Zeiger am Ende des Befehls auf den vorvorletzten Datensatz zeigt. Außerdem sollte man so etwas auf keinen Fall in der printf-Anweisung machen, da die Reihenfolge der Abarbeitung (von links nach rechts, von rechts nach links, von der Mitte nach ganz unten) nicht garantiert ist.

    Wie kann man den Zeiger sonst auf den nächsten "Satz" umleiten?

    Schon mit buffer++ ... allerdings musst Dir den ursprünglichen Wert von buffer für realloc() und free() merken. Ich denke, Du solltest buffer nicht antasten und stattdessen pp nehmen (bis jetzt nicht verwendet).

    Ich habe mal Dein Programm so verändert, dass es wenigstens auf einem Microsoft-Compiler fehlerfrei compiliert. Einen Test habe ich aber nicht gewagt, wahrscheinlich stürzt das Programm ab:

    // #include "header_malloc.h"
    #include <stdio.h>      // fflush, printf, scanf_s, scanf, stdin
    #include <stdlib.h>     // malloc, free, realloc, _msize (C11), exit
    #include <malloc.h>     // _msize (MS) - malloc.h ist Microsoft-spezifisch
    #include <string.h>     // strcpy
    
    #define HEAP_Faktor 5
    
    typedef struct
    {
    //rkhb: keine Umlaute!  char Geräte_Beschreibung[4000];
    //rkhb: keine Umlaute!  long int Geräte_Nummer;
    //rkhb: keine Umlaute1  int Stückzahl;
        char Beschreibung[4000];
        long int Nummer;
        int Anzahl;
    }Liste;
    
    //rkhb: Falscher Rückgabetyp. void main()
    int main (void)
    {
    // Kopf();
    
    Liste *buffer, *pp; //rkhb: Variable pp wird nicht verwendet
    int max,nummer=1;
    //rkhb: keine Umlaute. char Geräte_Beschreibung[4000];
    char Beschreibung[4000];
    printf("%31s  = %d\n\n","<HEAP_Faktor ",HEAP_Faktor);
    
    max=sizeof(Liste);
    buffer=(Liste*) malloc(HEAP_Faktor*max);
    if(buffer==NULL)
    {
        printf("%51s\n","malloc<>-Meldung: Nicht gen\x81gend HEAP vorhanden!"),free(buffer);exit(1);
    }
    
    printf("%34s = %p\n","**** HEAP-Adresse f\x81r 1. Ger\x84t",buffer);
    printf("%24s%s =%12d Bytes","**** HEAP-Gesamtgr\x94\xE1","e",_msize(buffer));
    
    do
    {
        printf("\n\n %d. Ger\x84t",nummer);
        //rkhb: _msize ist Microsoft-spezifisch
        if(nummer>1&&_msize(buffer)-(nummer-1)*max==0)  //Start bei nummer=0
        {
            buffer=(Liste *) realloc(buffer,_msize(buffer)+max*HEAP_Faktor);
            printf("%s%p"," <...HEAP wurde verschoben nach Adr ",buffer);
            printf("\n%34s%s%6d Bytes","...neue HEAP-Gesamtgr\x94\xE1","e     =",_msize(buffer));
            printf("\n%41s%6d Bytes\n","...noch freier HEAP-Speicher =",_msize(buffer)-((nummer-1)*max));
    
        }
        printf("\n%33s"," - Bezeichung <Ende mit \"0\">: ");
    //rkhb: keine Umlaute, keine Referenz auf Array.    scanf_s("%18s",&Geräte_Beschreibung,4000);
        scanf_s("%18s",Beschreibung,4000); //rkhb: scanf_s ist Microsoft-spezifisch (oder C11)
    
        fflush(stdin);  // rb: Windows-spezifisch
    //rkhb: keine Umlaute.  if(Geräte_Beschreibung[0]=='0') break;
        if(Beschreibung[0]=='0') break;
        else
        {
    //rkhb: keine Umlaute.      strcpy(buffer->Geräte_Beschreibung,Geräte_Beschreibung);
            strcpy(buffer->Beschreibung,Beschreibung);
            printf("%21s","- Ger\x84te_Nummer: ");
    //rkhb: keine Umlaute.      scanf("%li",&buffer->Geräte_Nummer);
            scanf("%li",&buffer->Nummer);
            fflush(stdin);      //rkhb: fflush(stdin) ist Windows-spezifisch
            printf("%14s","- Bedarf: ");
    //rkhb: keine Umlaute.      scanf("%d",&buffer->Stckzahl);
            scanf("%d",&buffer->Anzahl);
            fflush(stdin);      //rkhb: fflush(stdin) ist Windows-spezifisch
            pp=buffer;
            buffer++;//Fehlermeldung! Wie könnte man dann den Zeiger weiterschalten um weitere Einträge abzuspeichern?
            nummer++;
            printf("%37s%d Bytes","...freier HEAP_Speicher = ",_msize(buffer)-((nummer-1)*max));
    
        }
    
    }while(1);
    
    printf("\n\n Einkaufliste:");
    printf("\n =============");
    printf("\n\n Pos. Ger\x84tebezeichung Nummer Bedarf");
    printf("\n -------------------------------------");
    for(int i=1; i<nummer;i++)
    {
    //rkhb: keine Umlaute.  printf("\n%3d%19s%7li%5i",i,(--buffer)->Geräte_Beschreibung,(--buffer)->Geräte_Nummer,(--buffer)->Stückzahl);
        printf("\n%3d%19s%7li%5i",i,(--buffer)->Beschreibung,(--buffer)->Nummer,(--buffer)->Anzahl);
    }
    printf("\n\n-----------------------------------------------------------------------\n");
    }
    

    viele grüße
    ralph


  • Mod

    rkhb schrieb:

    --buffer verändert die Variable buffer , sodass der Zeiger am Ende des Befehls auf den vorvorletzten Datensatz zeigt. Außerdem sollte man so etwas auf keinen Fall in der printf-Anweisung machen, da die Reihenfolge der Abarbeitung (von links nach rechts, von rechts nach links, von der Mitte nach ganz unten) nicht garantiert ist.

    Schlimmer noch: Es ist UB.



  • ...



  • Hallo rhkb danke für die schnelle Antwort.
    Wie du schon vorausgesehen hast, dein Programm-Code stürzt ab.
    Der Compiler hat bereits meinen Code übersetzt und keinen Fehler gefunden. Ich verwende das Programm "Microsft Visual Studio", deshalb verwende ich auch einige
    Microsoft-spezifische Funktionen.

    Ich habe jetzt mein Programm wie folgt umgeschrieben: (in der Header-Datei befinden sich alle notwendigen Bibliotheken)

    #include "header_malloc.h"
    #define HEAP_Faktor 1
    
    typedef struct 
    {
    	char Geräte_Beschreibung[4000];
    	long int Geräte_Nummer;
    	int Stückzahl;
    }Liste;
    
    Liste * Einlesen(int *Anzahl); 
    void Ausgeben(Liste *, int); 
    
    void main()
    {
    Kopf(); 
    Liste *buffer;
    int nummer=1;
    int *zeiger;
    zeiger=&nummer;
    printf("%31s  = %d\n\n","<HEAP_Faktor ",HEAP_Faktor); 
    buffer= Einlesen(zeiger);
     Ausgeben(buffer,nummer); 
    }
    
    Liste * Einlesen(int *nummer)
    {
    int max;
    max=sizeof(Liste);
    Liste *buffer;
    buffer	=(Liste*) malloc(HEAP_Faktor*max); 
    if(buffer==NULL)
    {
    printf("%51s\n","malloc<>-Meldung: Nicht gen\x81gend HEAP vorhanden!"),free(buffer);exit(1); 
    }
    
    printf("%34s = %p\n","**** HEAP-Adresse f\x81r 1. Ger\x84t",buffer); 
    printf("%24s%s =%12d Bytes","**** HEAP-Gesamtgr\x94\xE1","e",_msize(buffer)); 
    
    do
    {
    	printf("\n\n %d. Ger\x84t",*nummer);
    	if(*nummer>1&&_msize(buffer)-(*nummer-1)*max==0)	
    	{
    	buffer=(Liste *) realloc(buffer,_msize(buffer)+max*HEAP_Faktor);	
    	printf("%s%p"," <...HEAP wurde verschoben nach Adr ",buffer); 
    	printf("\n%34s%s%6d Bytes","...neue HEAP-Gesamtgr\x94\xE1","e     =",_msize(buffer)); 
    	printf("\n%41s%6d Bytes\n","...noch freier HEAP-Speicher =",_msize(buffer)-((*nummer-1)*max)); 
    
    	}
    	printf("\n%33s"," - Bezeichung <Ende mit \"0\">: "); 
    	scanf_s("%18s",(buffer+(*nummer-1))->Geräte_Beschreibung,4000); 
    	fflush(stdin);
    	if((buffer+(*nummer-1))->Geräte_Beschreibung[0]=='0') break;
    	else
    	{
    
    		printf("%21s","- Ger\x84te_Nummer: "); 
    		scanf("%li",&(buffer+(*nummer-1))->Geräte_Nummer);		
    		fflush(stdin); 
    		printf("%14s","- Bedarf: ");				
    		scanf("%d",&(buffer+(*nummer-1))->Stückzahl);
    		fflush(stdin);
    		(*nummer)++;
    		printf("%37s%d Bytes","...freier HEAP_Speicher = ",_msize(buffer)-((*nummer-1)*max)); 	
    	}
    
    }while(1);
    return buffer; 
    }
    
    void Ausgeben(Liste *t, int nummer)
    {
    
    printf("\n\n Einkaufliste:");
    printf("\n =============");
    printf("\n\n Pos. Ger\x84tebezeichung Nummer Bedarf");
    printf("\n -------------------------------------");
    int k=0; 
    for(int i=1; i<nummer;i++,k++)
    {
    
    	printf("\n%3d%19s%7li%5i",i,(t+k)->Geräte_Beschreibung,(t+k)->Geräte_Nummer,(t+k)->Stückzahl);
    
    }
    printf("\n\n-----------------------------------------------------------------------\n");
    }
    

    Auf diese Lösungen bin ich aber nur durch langes Probieren gekommen.
    Könnte mir jemand eine Lösung zeigen wie ich es ledeglich mit den Zeigern buffer,pp klappt?

    #Wutz: Danke für den Tipp, aber ich habe mich hier eig. nicht angemelden um mein herausragendes Deutsch an den Mann zu bringen. 😉



  • ...



  • Was soll denn dieser aufgeblähte Müll?
    Willst du zeigen, dass du eine simple Aufgabenstellung mit 262 Zeilen Nicht-ANSI C Code erschlagen kannst?



  • ThomasWa. schrieb:

    verwende das Programm "Microsft Visual Studio",

    Dann arbeitest du mit dem C++ Compiler, d.h. arbeitest nicht mit C.
    Das wiederum heißt, dass du (und höchstwahrscheinlich dein Professor) nicht weißt, was du tust.
    C und C++ sind verschiedene Programmiersprachen und nur Anfänger/Fachbuchautoren/Hoch-/Dorfschullehrer behaupten was anderes.



  • ...



  • Hallo ThomasWa.

    Der Code ist in der jetzigen Form ziemlich für die Tonne.
    Wenn Du weiterhin darauf bestehst nicht konformes C zu verwenden, ist ein Forum für Standard C der falsche Platz für Dein Problem.
    Dann setz Dich mit Deinen Kommilitonen hin und Ihr kaut das gemeinsam durch.

    Ansonsten:
    Ich bin mir auch sicher, dass der - pardon - Undurchsichtige-Scheiss-Quelltext Ursache für Dein Problem ist.

    Wo ist denn das Problem ein Array durchzugehen?
    Du kannst Zeigerarithmetik benutzen, oder Arrayelemente über Ihren index ansprechen.

    #include <stdlib.h>
    #include <stdio.h>
    
    // Zeigerarithmetik
    void fill(int *p, int n, int val){
      while(n--)
        *p++ = val;
    }
    
    // Index
    void print(const int *p, int n){
      for(int i=0; i<n; ++i)
        printf("p[%d]=%d\n", i, p[i]);
    }
    
    int main(){
      const size_t n = 5;
      int *p = malloc(sizeof(int)*n);
      fill(p, n, 42);
      print(p, n);
      free(p);
    }
    


  • Nehme das folgende Programm als Lernhilfe für dich und deine Mitstreiter und nicht das Prof.Gefasel:

    http://ideone.com/H1wtp9

    #include <stdio.h>
    #include <stdlib.h>
    #ifdef __cplusplus
    #error ich bin ein depp
    #endif
    
    typedef struct
    {
      char beschreibung[20];
      long int nummer;
      int bedarf;
    } Geraet;
    
    int main()
    {
      Geraet *liste=0;
      int i=0;
      while(liste=realloc(liste,++i*sizeof*liste))
      {
        printf("\n%33s"," - Bezeichung <Ende mit \"0\">: ");
        scanf("%19[^\n]",liste[i-1].beschreibung); while(!feof(stdin)&&!ferror(stdin)&&getchar()!='\n');
        if(liste[i-1].beschreibung[0]=='0') break;
        printf("%21s","- Geräte_Nummer: ");
        if( 1!=scanf("%ld",&liste[i-1].nummer) ) break; while(!feof(stdin)&&!ferror(stdin)&&getchar()!='\n');
        printf("%14s","- Bedarf: ");
        if( 1!=scanf("%d",&liste[i-1].bedarf) ) break; while(!feof(stdin)&&!ferror(stdin)&&getchar()!='\n');
      }
      --i;
      while(i--)
        printf("\n%3d%19s%7li%5i",i+1,liste[i].beschreibung,liste[i].nummer,liste[i].bedarf);
      free(liste);
      return 0;
    }
    

    Es ist standardkonform (suche via Google, was das bedeutet), kurz und verfügt sogar über einfache Fehlerbehandlungen.



  • Super! Dankeschön 🙂



  • Wutz schrieb:

    Nehme das folgende Programm als Lernhilfe für dich und deine Mitstreiter und nicht das Prof.Gefasel:

    http://ideone.com/H1wtp9

    #include <stdio.h>
    #include <stdlib.h>
    #ifdef __cplusplus
    #error ich bin ein depp
    #endif
    
    typedef struct
    {
      char beschreibung[20];
      long int nummer;
      int bedarf;
    } Geraet;
    
    int main()
    {
      Geraet *liste=0;
      int i=0;
      while(liste=realloc(liste,++i*sizeof*liste))
      {
        printf("\n%33s"," - Bezeichung <Ende mit \"0\">: ");
        scanf("%19[^\n]",liste[i-1].beschreibung); while(!feof(stdin)&&!ferror(stdin)&&getchar()!='\n');
        if(liste[i-1].beschreibung[0]=='0') break;
        printf("%21s","- Geräte_Nummer: ");
        if( 1!=scanf("%ld",&liste[i-1].nummer) ) break; while(!feof(stdin)&&!ferror(stdin)&&getchar()!='\n');
        printf("%14s","- Bedarf: ");
        if( 1!=scanf("%d",&liste[i-1].bedarf) ) break; while(!feof(stdin)&&!ferror(stdin)&&getchar()!='\n');
      }
      --i;
      while(i--)
        printf("\n%3d%19s%7li%5i",i+1,liste[i].beschreibung,liste[i].nummer,liste[i].bedarf);
      free(liste);
      return 0;
    }
    

    Es ist standardkonform (suche via Google, was das bedeutet), kurz und verfügt sogar über einfache Fehlerbehandlungen.

    offensichtlich kann man auch standardkonformen müll programmieren.
    insofern ist es in der tat eine lernhilfe, nämlich, wie man es nicht machen darf.
    um mal die wesentlichen punkte zu nennen:

    der code kann ein speicherleck verursachen, bedingt durch dilettantische benutzung von realloc.
    der code enthält umständliches indizierungs/dekrementierungsgefrickel.

    um tipparbeit zu sparen, verweise ich bezüglich der korrekten benutzung von realloc auf
    http://stackoverflow.com/questions/3331221/what-is-the-correct-usage-of-realloc-when-it-fails-and-returns-null
    und auf
    http://www.c-plusplus.net/forum/206606


Log in to reply