calloc() und free(): Gibt es einen eleganteren Weg das zu erledigen?



  • Hallo Community,

    Ich bin C-Anfänger (habe im Oktober vergangenen Jahres angefangen).
    Meine Frage bezieht sich auf dynamische Speicherverwaltung. Ich habe eine aufgabe, die mit CRC zu tun hat, aber das ist hier absolut unwichtig. Im Programm kam ich nicht drum herum dynamische Speicherverwaltung zu verwenden. Nun gehört zu jedem malloc(), calloc() etc. auch ein zugehöriges free(). Zunächst einmal der Code (unvollständig im Hinblick auf die Aufgabenstellung, aber soweit lauffähig und der Zwischenstand sind einige Debug-Zeilen:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    void eingabe_nutzd_generp(char*, char*, unsigned long*, unsigned long*, void*, void*);				//Eingabe von Nutzdaten und Generatorpolynom
    void* dateneingabe(char*, char**, unsigned long*);			//Eingabe der daten und ausgabe derer, sowie länge
    char xor_char();
    
    char xorchar(char a, char b)
    {
    	char erg;
    
    	return erg;
    }
    
    void* dateneingabe(char *typ, char **daten, unsigned long *laenge)
    {
    	char charbuf[80];
    
    	printf("Bitte geben Sie %s ein: ", typ);		//Daten eingeben (im Buffer)
    	scanf("%s", charbuf);
    
    	*laenge = strlen(charbuf);			//länge abspeichern
    
    	*daten = calloc(*laenge+1, sizeof(**daten));	//Speicher für die Daten+NULL anfordern
    
    	strncpy(*daten, charbuf, *laenge+1);		//Daten auf Buffer kopieren
    
    	return *daten;
    }
    
    void eingabe_nutzd_generp(char *nutzdaten, char *generatorpolynom, unsigned long *nutzdaten_laenge, unsigned long *generatorpolynom_laenge, void *free1, void *free2)					
    {
    	free1 = dateneingabe("die Nutzdaten" ,&nutzdaten, nutzdaten_laenge);
    	free2 = dateneingabe("das Generatorpolynom" ,&generatorpolynom, generatorpolynom_laenge);
    
    	printf("nd %s\ngp %s\n", nutzdaten, generatorpolynom);						//Debug
    	printf("ndl %ld\ngpl %ld\n", *nutzdaten_laenge, *generatorpolynom_laenge);
    }
    
    int main(void)
    {
    	char *nutzdaten, *generatorpolynom;
    	unsigned long nutzdaten_laenge, generatorpolynom_laenge;
    	void *nutz, *gener;
    
    	eingabe_nutzd_generp(nutzdaten, generatorpolynom, &nutzdaten_laenge, &generatorpolynom_laenge, nutz, gener);		//eingabe
    
    	free(nutz);
    	free(gener);
    	return 0;
    }
    

    In "dateneingabe()" verwende ich die calloc()-Funktion. Die Adresse "*daten" geht interessanterweise verloren, aus dem Grunde habe ich die Funktion so anpassen müssen, dass sie die Adresse zurückgibt. Jetzt ist "dateneingabe()" nur leider eine Funktion, die von "eingabe_nutzd_generp()" aufgerufen wird und dort kann ich nicht mehr mit return arbeiten, da ich schon zwei Adressen angehäuft habe, die ich "befreien" muss. Aus dem Grunde habe ich noch mehr Parameter an die Funktion übergeben müssen...
    Ich habe den Verdacht, dass ich irgendwie die Adressen von "*nutzdaten" und "*generatorpolynom" verwenden könnte, mache ich das aber so, dann meldet Terminal, dass ich doch dort nie Speicher angefordert hätte.

    Nochmal: Programm funktioniert wie eine eins, aber ich habe das Gefühl, dass ich da Redundanz drin habe.

    Wie blöd stelle ich mich an? 😃



  • Schau dir doch mal die Werte von nutzdaten, generatorpolynom, nutz und gener in main an.

    Für Pointer hat printf den Formatspecifier %p.

    printf("nutzdaten : %p\n, nutzdaten);
    printf("nutz      : %p\n, nutz);
    

    Du kannst auch alle zusammengehörenden Werte in eine struct packen.



  • Ich habe deinen Code nicht wirklich verstanden und somit deine Frage nicht.
    Warum übergibst du die Länge bis nach main? Die brauchst du für dein free doch gar nicht.
    Du solltest dein calloc nicht in der untersten Funktions-Aufrufebene vornehmen, sondern mind. 1 Ebene drüber, und dann als Lokalspeicher, d.h. du brauchst dann überhaupt kein calloc/free.

    char* dateneingabe(char *typ, char *daten)
    {
        printf("Bitte geben Sie %s ein: ", typ);        //Daten eingeben (im Buffer)
        scanf("%79[^\n]", daten);
        return daten;
    }
    
    void eingabe_nutzd_generp(void)                  
    {
        char nutzdaten[80], generatorpolynom[80];
        dateneingabe("die Nutzdaten" ,nutzdaten);
        dateneingabe("das Generatorpolynom" ,generatorpolynom);
    
        printf("nd %s\ngp %s\n", nutzdaten, generatorpolynom);
    }
    


  • Hey,

    das mit der struct habe ich noch nicht implementiert, aber es ist eine gute Idee. Eins nach dem anderen jedoch. 😉

    Habe jetzt meinen Code angepasst, nachdem ich gesehen habe, dass "Nutz" auf 0x0 lag.

    ...
    
    void* dateneingabe(char *typ, char **daten, unsigned long *laenge)
    {
    	char charbuf[80];
    
    	printf("Bitte geben Sie %s ein: ", typ);		//Daten eingeben (im Buffer)
    	scanf("%s", charbuf);
    
    	*laenge = strlen(charbuf);			//länge abspeichern
    
    	*daten = calloc(*laenge+1, sizeof(**daten));	//Speicher für die Daten+NULL anfordern
    
    	strncpy(*daten, charbuf, *laenge+1);		//Daten auf Buffer kopieren
    
    	return *daten;
    }
    
    void eingabe_nutzd_generp(char **nutzdaten, char **generatorpolynom, unsigned long *nutzdaten_laenge, unsigned long *generatorpolynom_laenge)					
    {
    	dateneingabe("die Nutzdaten" ,nutzdaten, nutzdaten_laenge);
    	dateneingabe("das Generatorpolynom" ,generatorpolynom, generatorpolynom_laenge);
    
    	printf("nd %s\ngp %s\n", *nutzdaten, *generatorpolynom);						//Debug
    	printf("ndl %ld\ngpl %ld\n", *nutzdaten_laenge, *generatorpolynom_laenge);
    }
    
    int main(void)
    {
    	char *nutzdaten, *generatorpolynom;
    	unsigned long nutzdaten_laenge, generatorpolynom_laenge;
    
    	eingabe_nutzd_generp(&nutzdaten, &generatorpolynom, &nutzdaten_laenge, &generatorpolynom_laenge);		//eingabe
    
    	free(nutzdaten);
    	free(generatorpolynom);
    	return 0;
    }
    

    Jetzt habe ich mein Problem auch selbst gelöst. Es ging darum, dass ich bei call-by-reference auch die Referenz auf einen Pointer übergeben muss. Das ist ursprünglich schiefgelaufen. Jetzt sind die überflüssigen Sachen weg. Danke für den Dominostein, der alles andere endlich umgeschmissen hat! 🙂

    @Wutz (Ich habe deinen Beitrag etwas später erst gesehen, deswegen im P.S.): Ich sagte ja bereits, dass die eigentliche Aufgabe des Codes noch unerheblich ist, da er noch nicht fertig ist. Was er bisher tun soll ist: Zwei binäre zahlen (Nutzdaten, Generatorpolynom) vom Benutzer abfragen und diese, sowie deren Länge abspeichern. Ich brauche die Länge in Main weil ich damit in weiteren, aus main aufgerufenen Funktionen, arbeiten muss.
    Wenn ich aber kein calloc/free verwende verschwende ich Speicherplatz! Die Zeichenketten werden nicht immer 80 Zeichen lang sein. Wahrscheinlich habe ich damit sogar den Buffer überdimensioniert, aber das ist ja auch nicht das entscheidende. Klar, ich hätte auch die Holzmethode gehen können und sagen können "Ich gebe allen 80 Byte!", aber genau DAS wollte ich verhindern. 🕶
    oder habe ich dich da falsch verstanden?



  • Wenn du Strings übergibst, hast du mit strlen jederzeit die Möglichkeit, die Länge zu bestimmen.
    Ein calloc ist sehr viel teurer als ein auto Speicher, der wiederum auch noch exceptionsicher ist.


Log in to reply