Pointerfrage: Übergabe und Speicheroptimierung von Zeichenketten



  • Hallo Forum,

    ich frage mich wie man wohl am sparsamsten globale String-Variablen setzen kann. Ein String ist ja ein Array von chars. Wenn ich die Länge der Arrays bereits beim Start des Programms festlege würde automatisch Speicher verschwendet werden.

    Daher frage ich mich ob es sinnvoll ist die globalen Variablen als Pointer zu setzen, und der nachfolgende Code entsprechend geeignet ist:

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    #define BUFFSIZE 50
    
    char *NAME;
    
    int main (void) {
        char *namebuf;
        int length;
        namebuf = malloc(BUFFSIZE*sizeof(char));
        if (namebuf == NULL) {
            printf("FATAL, kann keinen Speicher für den Buffer beschaffen, EXIT\n");
            return 1;
        }
        printf("Starte test...\n");
        printf("Bitte gib deinen Namen ein: ");
        scanf("%s", namebuf);
        length = strlen(namebuf);
        printf("Länge des Namens: %d\n", length);
        NAME = malloc(length*sizeof(char));
        if (NAME == NULL) {
            printf("FATAL, kann keinen Speicher beschaffen, EXIT\n");
            return 1;
        }
        strcpy(NAME, namebuf);
        free(namebuf);
        printf("Inhalt von name: %s\n", NAME);
        return 0;
    }
    

    Das Programm funktioniert soweit.
    Ist das Vorgehen soweit ok, oder mache ich hier schwerwiegende Fehler?

    Ich habe versucht das Einllesen und Speichern von Daten von der EIngabe in eine Funktion zu kapseln:

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    #define BUFFSIZE 50
    
    char *NAME;
    
    void inputToCharPtr(char *text, char *buffer, char *ptr) {
        int length;
        printf("%s", text);
        scanf("%s", buffer);
        length = strlen(buffer);
        ptr = malloc(length*sizeof(char));
        if (ptr == NULL) {
            printf("FATAL, kann keinen Speicher beschaffen, EXIT\n");
            exit(1);
        }
        strcpy(ptr, buffer);
    }
    
    int main (void) {
        char *namebuf;
        namebuf = malloc(BUFFSIZE*sizeof(char));
        if (namebuf == NULL) {
            printf("FATAL, kann keinen Speicher für den Buffer beschaffen, EXIT\n");
            return 1;
        }
        printf("Starte test...\n");
        inputToCharPtr("Bitte gib deinen Namen ein: ", namebuf, NAME);
        free(namebuf);
        printf("Inhalt von name: %s\n", NAME);
        return 0;
    }
    

    Leider ist hier NAME immer (null). Ich schätze hier mache ich einen Fehler bei der Übergabe der Argumente. Kann mir hier jemand sagen welchen?

    Ich danke im Voraus!

    Gruß
    Sparrow



  • In der funktion inputToCharPtr solltest du ptr als call-by-ref übergeebn, weil
    sich die adresse der ptr in der funktion änder, und aushalb ohne CBR nicht übernommen wird. ich würde als rückgabe parameter der funktion den zeiger auf den ptr machen.

    void inputToCharPtr(char *text, char *buffer, char *&ptr){..
    
    ..
    };
    

    zudem solltest du im ein byte(char) für nen string mehr reservieren, weil das letze zeichen ein 0 sein muss, damit funktionen wie strcpy und strlen das ende des strings im speichrr erkennen. am besten du initialisierst den speicher noch mit "memset"

    ptr = malloc(length*sizeof(char)+1); //hier die +1
    


  • BorisDieKlinge schrieb:

    void inputToCharPtr(char *text, char *buffer, char *&ptr)
    

    adressoperator im funktionskopf?
    du meinst bestimmt *char *****ptr, oder?
    🙂



  • Hi !
    Da ja dein Pufferzeiger NAME global ist, kann deine Funktion im Prizip so aussehen:
    void inputToCharPtr(char *text);
    Einmal malloc aufrufen genügt:
    NAME = malloc( ...
    Die Anzahl der einzulesenden Zeichen kannst du mit scanf("%49", NAME);
    beschränken.
    In der Praxis jedoch, würde für Aufgaben dieser Art heutzutage wohl kaum jemand ernsthaft malloc benutzen.
    Oder hast du tatsächlich so wenig Arbeitsspeicher zur Verfügung?

    Grüße.



  • stimmt, bei c gibts keine referenzen dann meine ich

    **ptr:)
    


  • BorisDieKlinge schrieb:

    stimmt, bei c gibts keine referenzen dann meine ich

    **ptr:)
    

    in c gibts auch keine smileypointer



  • Vielen Dank für die vielen Antworten!

    Das Zielgerät wird nicht über sehr viel Speicher verfügen, außerdem wäre das nur verschwendeter Speicher, der ist gut benutzt besser aufgehoben.

    Was genau bedeuten denn die beiden Sternchen vor der Variablenbezeichnung? Einfach ein 2. davor schreiben funktioniert leider nicht:

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    #define BUFFSIZE 50
    
    char *NAME;
    
    void inputToCharPtr(char *text, char *buffer, char **ptr) {
        int length;
        printf("%s", text);
        scanf("%s", buffer);
        length = strlen(buffer);
        ptr = malloc(length*sizeof(char));
        if (ptr == NULL) {
            printf("FATAL, kann keinen Speicher beschaffen, EXIT\n");
            exit(1);
        }
        strcpy(ptr, buffer);
    }
    
    int main (void) {
        char *namebuf;
        namebuf = malloc(BUFFSIZE*sizeof(char));
        if (namebuf == NULL) {
            printf("FATAL, kann keinen Speicher für den Buffer beschaffen, EXIT\n");
            return 1;
        }
        printf("Starte test...\n");
        inputToCharPtr("Bitte gib deinen Namen ein: ", namebuf, NAME);
        free(namebuf);
        printf("Inhalt von name: %s\n", NAME);
        return 0;
    }
    

    Beim Übersetzen bekomme ich die folgenden Warnungen:

    sparrow@io:~/temp$ gcc -Wall -O3 -o test test.c
    test.c: In Funktion »inputToCharPtr«:
    test.c:20: Warnung: Übergabe des Arguments 1 von »strcpy« von inkompatiblem Zeigertyp
    test.c: In Funktion »main«:
    test.c:32: Warnung: Übergabe des Arguments 3 von »inputToCharPtr« von inkompatiblem Zeigertyp
    

    Könnt ihr mir nochmal unter die Arme greifen?

    Gruß
    Sparrow



  • sparrow schrieb:

    ptr = malloc(length*sizeof(char));
        if (ptr == NULL) {
            printf("FATAL, kann keinen Speicher beschaffen, EXIT\n");
            exit(1);
        }
        strcpy(ptr, buffer);
    
    *ptr = malloc(length);
        if (*ptr == NULL) {
            printf("FATAL, kann keinen Speicher beschaffen, EXIT\n");
            exit(1);
        }
        strcpy(*ptr, buffer);
    

    aber ansonsten ist der code doch ziemlich doof. warum das doppelte malloc?
    🙂



  • Hallo *-freak,

    ich dachte mir das ganze so:
    es gibt einen Buffer der die Daten aufnimmt die der Benutzer eingegeben hat. In diesem Fall seinen Namen.

    Dann gibt es globale Pointer die verschiedene Informationen aufnehmen und jeweils nur mit malloc die Größe erhalten die sie tatsächlich brauchen.

    Nach dem einlesen aller Informationen kann dann der Buffer der einließt entfernt werden.

    In diesem Beispiel ist das natürlich nicht besonders einleuchtend, aber ich könnte mir vorstellen, dass es hilfreich ist wenn ich nicht nur den Namen sondern mehr Daten eingeben lassen möchte:

    inputToCharPtr("Bitte gib deinen Vornamen ein: ", buffer, VNAME);
    inputToCharPtr("Bitte gib deinen Namen ein: ", buffer, NNAME);
    inputToCharPtr("Bitte gib dein Lieblingstier ein: ", buffer, TIER);
    

    Den Buffer könnte ich natürlich gleich als Array initialisieren. Allerdings weiß ich da nicht wie ich den Speicher vom Array hinterher wieder frei gebe, deshalb habe ich das im Augenblick auch über malloc gemacht.

    Vielen Dank!

    Sparrow

    EDIT

    Aber es funktioniert leider noch immer nicht:

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    #define BUFFSIZE 50
    
    char *NAME;
    
    void inputToCharPtr(char *text, char *buffer, char **ptr) {
        int length;
        printf("%s", text);
        scanf("%s", buffer);
        length = strlen(buffer);
        *ptr = malloc(length+1);
        if (*ptr == NULL) {
            printf("FATAL, kann keinen Speicher beschaffen, EXIT\n");
            exit(1);
        }
        strcpy(*ptr, buffer);
    }
    
    int main (void) {
        char *namebuf;
        namebuf = malloc(BUFFSIZE*sizeof(char)+1);
        if (namebuf == NULL) {
            printf("FATAL, kann keinen Speicher für den Buffer beschaffen, EXIT\n");
            return 1;
        }
        printf("Starte test...\n");
        inputToCharPtr("Bitte gib deinen Namen ein: ", namebuf, NAME);
        free(namebuf);
        printf("Inhalt von name: %s\n", NAME);
        return 0;
    }
    
    sparrow@terra:~/temp$ gcc -O3 -Wall -o testd test.c
    test.c: In Funktion »main«:
    test.c:32: Warnung: Übergabe des Arguments 3 von »inputToCharPtr« von inkompatiblem Zeigertyp
    

    Beim Ausführen:

    sparrow@terra:~/temp$ ./testd
    Starte test...
    Bitte gib deinen Namen ein: test
    Segmentation fault (core dumped)
    


  • Ich denke, du wolltest die Adresse von NAME übergeben. Also in Z 32:

    inputToCharPtr("Bitte gib deinen Namen ein: ", namebuf, &NAME);
    


  • sparrow schrieb:

    Könnt ihr mir nochmal unter die Arme greifen?
    Gruß
    Sparrow

    Das scheint nicht so zu fruchten. Du hast ja schon so einige nützliche Tips bekommen und machst den gleichen Bockmist wieder von vorn.
    Du musst die Anzahl der Zeichen, die du einliest begrenzen, sonst macht dein
    Programm spätestens an der Stelle
    strlen(buffer)
    nen Klappmann, wenn einer mehr als BUFFSIZE Zeichen eingibt.



  • B.B. schrieb:

    sparrow schrieb:

    Könnt ihr mir nochmal unter die Arme greifen?
    Gruß
    Sparrow

    Das scheint nicht so zu fruchten. Du hast ja schon so einige nützliche Tips bekommen und machst den gleichen Bockmist wieder von vorn.
    Du musst die Anzahl der Zeichen, die du einliest begrenzen, sonst macht dein
    Programm spätestens an der Stelle
    strlen(buffer)
    nen Klappmann, wenn einer mehr als BUFFSIZE Zeichen eingibt.

    Ich hab das schon verstanden, nur handelt es sich hierbei ja um ein Beispielprogramm das für mich nur die Frage klären soll was ich bei der Übergabe der Pointer falsch mache.
    Die länge der Eingabe ist für mich eher nebensächlich.

    angelhaken schrieb:

    Ich denke, du wolltest die Adresse von NAME übergeben. Also in Z 32:

    inputToCharPtr("Bitte gib deinen Namen ein: ", namebuf, &NAME);
    

    Ah, das wars. Ich danke dir! Ich hab mich so auf die Funktion konzentriert, dass ich den Fehler dort nicht gesehen habe.

    Man übergibt also die Adresse und die beiden ** bedeuten sowas wie Zeiger auf einen Zeiger?

    Danke an alle
    Sparrow



  • Man übergibt also die Adresse und die beiden ** bedeuten sowas wie Zeiger auf einen Zeiger?

    Ja.


Log in to reply