Pointer, Char, Malloc Problem (mal wieder :-( )



  • Hallo Leute,

    hab jetzt ne Zeit nicht weiter gemacht mit C lernen, wollte jetzt mal etwas Dateiarbeit usw. machen aber ich scheitere (mal wieder ) an Pointer bzw. malloc.
    Ich dachte echt ich hab´s gefressen.
    Kann mal jmd. drüber sehen bitte?

    Hier mein Code:
    system.h

    #include <stdio.h>
    #include <stdlib.h>
    #define smax 20
    #define malmax 60
    
    void div_save(const char *name);
    char* cfn(char* name, char* extension);
    

    cfn.c (create filename)

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "system.h"
    
    char* cfn(char* name, char* extension){
    
    size_t len1, len2;
    char* buffer;
    
    buffer = malloc (smax);
    len1= strlen(name);
    len2= strlen(extension);
    
    name[len1-1]=0;
    extension[len2-1]=0;
    
    strcpy(buffer, name);
    strcat(buffer, extension);
    
    return buffer;      
    free(buffer); // Dieser Speicher wird wahrscheinlich nie frei??       
    
          }
    

    main.c

    #include <stdio.h>
    #include <stdlib.h>
    #include "system.h"
    int main(int argc, char *argv[])
    {
    
    char test1[smax];
    char test2[smax];
    char * datname1;
    
    puts("Dateinamen eingeben: ");
    fgets(test1, smax-1, stdin);
    puts("Dateiendung mit Punkt eingeben: ");
    fgets(test2, smax-1, stdin);
    
    datname1=malloc(malmax);
    datname1=cfn(test1, test2);
    
    div_save(datname1);
    free(datname1); 
    
      system("PAUSE");	
      return 0;
    }
    

    und hier happerts dann extrem:
    div_save.c

    #include <stdio.h>
    #include <stdlib.h>
    #include "system.h"
    
    void div_save(const char *name){
    /*VAR                         */ 
    char *fname;
    size_t len;
    FILE *fptr;
    /*End_VAR                     */ 
    
    puts("run");
    
    name=malloc(malmax);
    
    puts(name);
    free(name);
    }
    

    Also div_save soll später mal ne Datei erstellen oder da was reinspeichern.

    Jetzt ist das Problem aber, wenn ich nur kurze Dateinamen und Endungen eingebe, z.b.b. test1= ddddddd test2= .txt dann funktioniert alles (wenn ich kein malloc benuzte... was ja eigentlich falsch ist? ), puts(name) funktioniert. Aber das ist wohl zufall.

    Wenn ich zum testen nen "Blödsinn" eingebe, z.B. test1=mmmmmmmmmmmmmmmmmmmmmmmmm

    dann stürzt mein Programm nach puts("run") ab.
    Aber ich brauch doch malloc um Speicher für den "String" zu reservieren, ich weiß ja nicht wirklich was da reinkommen könnte??

    Wenn ich keinen malloc benuzte, kann ich puts(name) ausführen , aber nur bei "kurzen" eingaben.



  • Du hast da ein paar sehr üble Fehler im Programm:

    datname1=malloc(malmax);
    datname1=cfn(test1, test2);
    

    ⚠ nicht machen!
    Daurch verlierst du den Verweis auf den Speicher von malloc. Den bekommst du nicht wieder und kannst somit den Speicher auch nicht nehr freigeben.
    Lass das malloc weg.

    name=malloc(malmax);
    puts(name);
    

    ⚠ Welchen Inhalt soll den puts da ausgeben? Da steht doch noch gar nichts.
    Nimm calloc. Dann sind da Nullen (Was einem Leerstring entspricht)

    Ja, der Speicher in cfn wird nicht frei gegeben.
    Allerdings machst du das in Zeile 20 von main.

    Und fgets legt das '\n' von der Entertaste mit im Array ab.
    Dann hast du Dateinamen mit Newline drin. Das ist sehr schlecht.
    Bei fgets gibt man auch die ganze Speichergröße an. (Das mit dem -1 ist bei scanf)

    Und was soll

    name[len1-1]=0;
    extension[len2-1]=0;
    

    😕
    Wenn der String keine 0 hat, funktioniert strlen schon nicht.



  • C:

    name=malloc(malmax);
    puts(name);

    Welchen Inhalt soll den puts da ausgeben? Da steht doch noch gar nichts.
    Nimm calloc. Dann sind da Nullen (Was einem Leerstring entspricht)

    Eigentlich soll puts hier den Inhalte des "übergebenen" Strings ausgeben.
    Ich glaube ich hab da was mit dem Malloc falsch verstanden.

    Wenn ich einer funktion , z.B.: char *myString übergeben, muss ich doch für myString Speicher reservieren, da ich ja nicht weiß wieviel da "reinkommt" ? oder sehe ich das falsch? Und das , davon bin ich ausgegangen, macht man mit malloc??

    Und was soll

    C:

    name[len1-1]=0;
    extension[len2-1]=0;

    ähmmmm,,, hustel, damit wollte ich die "newlines" löschen und aus 2 Namen, einen machen... Das hat eigentlich im Zusammenhang mit dem restlichen Code funktioniert. (Ist aber wohl nicht die schönste Art...)

    Du hast da ein paar sehr üble Fehler im Programm:

    C:

    datname1=malloc(malmax);
    datname1=cfn(test1, test2);

    nicht machen!
    Daurch verlierst du den Verweis auf den Speicher von malloc. Den bekommst du nicht wieder und kannst somit den Speicher auch nicht nehr freigeben.
    Lass das malloc weg.

    Tja.. da sind wir wohl wida bei meinem Verständnissproblem? cfn gibt nen Pointer auf Char zurück, da ich nicht weiß wie "groß", muss ich doch irgendwie für den Pointer "datname1" speicher reservieren?

    Mann mann mann, ich wollte was mit Dateienspeichern probieren, aber soweit komm ich echt nicht. Verdammt.



  • Wenn du einer Funktion einen Namen mitteilst, dann muss der doch schon irgendwo stehen. Also gibt es doch schon Speicher dafür.

    Was reingeht in die Funktion muss bekannt sein.

    beginner88888 schrieb:

    Tja.. da sind wir wohl wida bei meinem Verständnissproblem? cfn gibt nen Pointer auf Char zurück, da ich nicht weiß wie "groß", muss ich doch irgendwie für den Pointer "datname1" speicher reservieren?

    Bei dir wird doch der Speicher vom malloc in cfn besorgt.
    Was allerdings kein guter Stil ist.

    Besser, die aufrufende Funktion kümmert sich um den Speicher. Freigeben muss sie ihn sowieso.

    char* cfn(char *buffer, size_t len, char* name, char* extension){
     // cfn ist es völlig egal, ob buffer ein Array ist oder dynamischer Speicher.
    
      size_t len1, len2;
    
      len1= strlen(name);
      len2= strlen(extension);
    
      name[len1-1]=0;
      extension[len2-1]=0;
    
      strcpy(buffer, name);
      strcat(buffer, extension);
    
      return buffer;      
    
    }
    
    // Aufruf
    
    datname1=malloc(malmax);
    datname1=cfn(datname1, malmax, test1, test2); // das datname1= kannst du auch weglassen
    ....
    free(datname1);
    

    beginner88888 schrieb:

    Mann mann mann, ich wollte was mit Dateienspeichern probieren, aber soweit komm ich echt nicht. Verdammt.

    Dann beschäftige dich doch mit dem Dateien speichern und nicht mit der dynamischen Speicherverwaltung. Was du da machst geht auch mit Arrays. Du machst sie groß genug, dann passt das.

    Das mit dem newline ist erstmal ok (mein Fehler)



  • Besser, die aufrufende Funktion kümmert sich um den Speicher. Freigeben muss sie ihn sowieso.

    C:

    char* cfn(char *buffer, size_t len, char* name, char* extension){
    // cfn ist es völlig egal, ob buffer ein Array ist oder dynamischer Speicher.

    size_t len1, len2;

    len1= strlen(name);
    len2= strlen(extension);

    name[len1-1]=0;
    extension[len2-1]=0;

    strcpy(buffer, name);
    strcat(buffer, extension);

    return buffer;

    }

    // Aufruf

    datname1=malloc(malmax);
    datname1=cfn(datname1, malmax, test1, test2); // das datname1= kannst du auch weglassen
    ....
    free(datname1);

    // cfn ist es völlig egal, ob buffer ein Array ist oder dynamischer Speicher.

    Ist dafür in der Funktion dann size_t len ?? Weil das wird ja in der Funktion nicht verwendet?



  • Die Funktion kann nicht feststellen wie groß der Speicher hinter dem Zeiger buffer ist (bei name und extension ebenso).

    Daher solltest du der Funktion die Größe übergeben, damit es nicht zu einem Pufferüberlauf kommt. (so wie bei gets)

    Es fehlt also noch die Überprüfung, ob genug Platz ist.

    if (len1+len2+1 > len)
      return NULL;
    

    Oder du gehst sicher, immer genug Speicher zu übergeben.



  • Danke erstmal. Werd das ganze nochmal überarbeiten.

    Zusammenfassend, wenn in der Aufrufenden Funktion schon Speicher reserviert wurde, brauch ich für nen "Char-Pointer" in der Funktion (also der übergebenen) keinen Speicher mehr reservieren?



  • So... hier die überarbeitet Version

    cfn.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "system.h"
    
    char* cfn(char* buffer, size_t max_gr, char* name, char* extension){
    
    size_t len1, len2;
    
    len1=strlen(name);
    len2=strlen(extension);
    
    if ((len1+len2) > max_gr )
       return NULL;
    
    name[len1-1]=0;
    extension[len2-1]=0;
    
    strcpy(buffer, name);
    strcat(buffer, extension);
    
    return buffer; 
    
    }
    

    main.c

    #include <stdio.h>
    #include <stdlib.h>
    #include "system.h"
    int main(int argc, char *argv[])
    {
    
    char test1[smax];
    char test2[smax];
    char * datname1;
    
    puts("Dateinamen eingeben: ");
    fgets(test1, smax-1, stdin);
    
    puts("Dateiendung mit Punkt eingeben: ");
    fgets(test2, smax-1, stdin);
    
    datname1=malloc (malmax); 
    cfn(datname1,malmax,  test1, test2);
    if (datname1 != NULL)
       puts(datname1);
    div_save(datname1);
    
    free(datname1);
    
      system("PAUSE");	
      return 0;
    }
    

    und hier.... Mein Versuch Strukturen in Dateien zu speichern und wieder zu lesen:

    #include <stdio.h>
    #include <stdlib.h>
    #include "system.h"
    
    void div_save( char *name){
    FILE *save, *open;
    struct daten test1, test2;
    
    if ( (save= fopen( name, "w")) != NULL )
       puts("File opened/created");
       else
       puts("Error FILE not opended or created"); 
    
    puts("Insert Produkt-Name");
    fgets(test1.name, smax, stdin);
    
    puts("Insert Produkt-ID");
    scanf("%d", &test1.ID);
    
    puts("Insert Status");
    fflush(stdin);
    scanf("%c", &test1.status);
    
    printf("%s%d\n%c\n", test1.name, test1.ID, test1.status);
    
     fwrite(&test1,  sizeof(  test1),1,  save);  
    
     puts("saved");
     fclose(save);
    
    if ( (open=fopen(name, "r")) != NULL )
        puts("opened");
        else
        puts("error opening");
    
     fread(&test2, sizeof(test2), 1, open);
     puts(test2.name),
     printf("%d", test2.ID);
     printf("\n%c", test2.status);
    
     fclose(open);
    
         }
    

    Also was soll ich sagen... Einfaches Schreiben, einfaches Lesen.
    Es funktioniert. Aber ich habe nicht den Eindruck das es so richtig gemacht ist.
    Wenn die Datei, z.B.: test1.txt heißt und ich mach die auf... Bis auf den "String" sind alles Hyroglyphen. Aber wie gesagt, ich kanns dann "richtig" auslesen.

    Eine "gemischte" Struktur zu schreiben , scheint mir jetzt nicht gaaaanz so einfach....

    Ach ja, die Struct ist in System.h definiert:

    struct daten{char name[smax]; int ID; char status;};
    


  • Es ist voellig normal, wenn du "Hyroglyphen" siehst. Du hast wohl noch nie in eine Binaerdatei reingeschaut.

    - fflush(stdin); ist Müll
    - wenn save==NULL, machst du weiter statt rauszugehen



  • beginner88888 schrieb:

    Wenn die Datei, z.B.: test1.txt heißt und ich mach die auf... Bis auf den "String" sind alles Hyroglyphen.

    Du schreibst mit fwrite die Daten genau so in die Datei, wie sie im Speicher stehen. Wenn du (als Mensch) sie lesen willst, musst du die ZAhlen vorher in strings umwandeln.
    Dazu ist fprintf da.

    beginner88888 schrieb:

    Aber wie gesagt, ich kanns dann "richtig" auslesen.

    Da gibt es viele Fallen, in die man rennen kann.
    Solange du nur auf dem selben System arbeitest ist das in Ordnung.
    Aber in C ist ja schon die Größe von int nicht eindeutig.
    Auch die Endianness kann unterschiedlich sein.
    Dann klappt das mit dem fread nicht mehr.

    Ein einfaches gängiges Format wäre noch CSV



  • ok, das mit dem fflush weiß ich eigentlich und wenn save==NULL hab ich übersehen. Sorry.

    Ehrlich gesagt Plattformunabhängig will ich jetzt momentan noch gar nicht sein 🙂

    Jetzt stellt sich das gößere Problem, an das ich ursprünglich schon mal dachte.

    Wenn ich meine Datei ein weiteres mal "öffne", mit fopen(name, "a") müsste der Dateizeiger am Ende stehen. Soweit so gut, ich kann also wieder eine Struktur dazu schreiben, es dürfte nichts überschrieben werden.

    Tja, nur wie lese ich die dann wieder aus???
    fread(??????) . Ich hab ja jetzt meine Struktur 2mal drinn stehen...
    Überlegung war :

    fread(&puffer1, .....)
    fread(&puffer2, .....) aber da wandert mir der Dateizeiger irgendwie nicht mit, bzw. in puffer2 ist ausser müll dann nicht viel drinnen.

    fseek... ?? Wäre das ein Lösungansatz?
    Aber Problem ist ja auch, wenn ich 2 Strukturen auslesen will, brauch ich ja nen "puffer", der 2 Strukturen aufnimmt... Array of Struct? Wah, ich dreah noch durch mit C.

    Ich habe das gefühl, mit dem Strukturen schreiben und lesen total auf dem Holzweg zu sein??

    Leute mal OFF-Topic.. Wie lange macht ihr "das" (C) schon ?? Ich hab mich schon in ein paar Programmiersprachen einlernen müssen ( THX GOD, brauchte selten was mit String´s), aber C haut mir immer wenn ich meine "Jetzt hab ich´s" wieder eine rein... Wah 😡 😡 😡



  • beginner88888 schrieb:

    Tja, nur wie lese ich die dann wieder aus???
    fread(??????) . Ich hab ja jetzt meine Struktur 2mal drinn stehen...
    Überlegung war :

    fread(&puffer1, .....)
    fread(&puffer2, .....)

    Ja, genau so.

    beginner88888 schrieb:

    aber da wandert mir der Dateizeiger irgendwie nicht mit, bzw. in puffer2 ist ausser müll dann nicht viel drinnen.

    Hast du sie nach dem schreiben bzw. anhängen wieder geschlossen und neu zum lesen geöffnet?



  • Hast du sie nach dem schreiben bzw. anhängen wieder geschlossen und neu zum lesen geöffnet?

    Ja, hab sie mit fclose zugemacht und mit fopen (..."a") wieder auf gemacht.
    Aber das :

    fread(&puffer1, sizeof(puffer1), 1, ptr);
    fread(&puffer2, sizeof(puffer2), 1, ptr);
    

    ...klappt nicht. Muss ich evtl. fread(&puffer1, sizeof(puffer1), 2, ptr) machen? nö is quatsch, 2 blöcke kopieren.

    Ich hab das "Programm" jetzt leider nicht mehr vorliegen, hab mich da "nebenbei" in der Arbeit etwas "gespielt".

    Aber prinzipell sollte der Zeiger mitwandern? Muss ich nochmal drüber sehen.

    Hat evtl. jmd. ein kurzes Bspl. mit gemischten Strukturen?

    Nochmal Danke, das du mir über meine Codehaufen rüber siehst.



  • beginner88888 schrieb:

    Ja, hab sie mit fclose zugemacht und mit fopen (..."a") wieder auf gemacht.

    fread ist lesen. Daetien zum lesen öffnen geht mit fopen(.., "r")
    Wobei das r in fread und das "r" bei fopen durchaus etwas miteinander zu tun haben.

    "a" öffnet zum schreiben und positioniert den Dateizeiger an das Dateiende. (kein lesen)
    "w" öffnet zum schreiben und positioniert den Dateizeiger an den Dateianfang. (kein lesen)
    Ein bestehende Datei wird vorher gelöscht (auf Länge 0 gesetzt).
    "r" öffnet zum lesenund und positioniert den Dateizeiger an den Dateianfang. (kein schreiben)

    Die Modi mit dem + zum lesen und schreiben sind auch nicht einfacher zu verstehen, da du zwischen lesen und schreiben den Dateizeiger selber bewegen musst.



  • Hallo Dirk, wei´s nicht genau wo gestern mein Fehler lag, aber heute ging´s.
    Hab nochmal das "Speichern usw. " überarbeitet.
    Mann verzeihe mir das fflush

    #include <stdio.h>
    #include <stdlib.h>
    #include "system.h"
    #define input  1
    #define output 2
    
    void dbank(const char *fname, const int ct_dbank){
    
    struct data ibuffer, obuffer[5];     
    FILE *save, *open;
    int choose=0;
    int i, j, k;
    char dummy;
    
    while (choose != 3) {
    
    system("cls");
    puts("######################################");
    puts("#   Daten Eingeben oder Auslesen?    #");
    puts("#       1=  Eingeben                 #");
    puts("#       2=  Auslesen                 #");
    puts("#       3=  EXIT                     #");
    puts("######################################");
    puts("\n");
    scanf("%d",&choose);
    
    switch (choose){
    
           case input   :  if ( (save=fopen(fname, "w")) != NULL)
                                puts("File Opened");
                                else{
                                 puts("Can´t open / Create File");
                                  return;
                                  }
                             for (i=0; i< ct_dbank; i++) {
                                 fflush(stdin);
                                 puts("Enter Name: ");
                                 fgets(ibuffer.name, smax, stdin);
                                 puts("Enter ID: ");
                                 scanf("%d", &ibuffer.id);
                                 fflush(stdin);
                                 puts("Enter Status: ");
                                 scanf("%c", &ibuffer.status);
                                 fwrite(&ibuffer, sizeof(ibuffer), 1, save);
                                 } 
                                 fclose(save); 
                           break;
    
           case output  :  if ( (open=fopen(fname, "r")) != NULL)
                                puts("File Opened");
                                else{
                                 puts("Can´t open / Create File");
                                  return;
                                  }
                           for (j=0; j< ct_dbank; j++) {
                               fflush(stdin);
                               fread(&obuffer[j], sizeof(obuffer[j]), 1, open);
                               }
                           fclose(open);
                           k=0;
                           while (k< ct_dbank) {
                                 printf("Name   : %s  ", obuffer[k].name);
                                 printf("ID     : %d  \n", obuffer[k].id);
                                 printf("Status : %c  \n", obuffer[k].status);
                                 puts("Press Any Key + 'Enter' to contiune");
                                 k++;
                                 dummy=getchar();
                                 fflush(stdin);
                                 }
    
                          break;
    
           default      : puts("Wrong Input"); return  ;
    
           }
    
    }     
    
    }
    

    Habe mich jetzt doch für ein Array of Struct entschieden.
    Muss noch ne Abfrage reinmachen, das nicht mehr ausgelesen werden dürfen, wie das Array Elemente hat.



  • Du solltest die Eingabe vom Speichern und die Ausgabe vom Lesen trennen.
    Das sind vier verschiedene Funktionen.



  • Wollte das jetzt noch umsetzten, hab aber jetzt ein Problem mit dem "Öffnen".

    Was hab ich übersehen, er erstellt mir die Datei usw, nur reinspeichern tut er nicht mehr.
    Wird die Datei beim verlassen des sub´s open wieder geschlossen? Oder stimmt einfach meine Rückgabe nicht?

    öffnen

    #include <stdio.h>
    #include <stdlib.h>
    #include "system.h"
    FILE* fileopen_w(FILE *ptr, const char* filename){
    
        if ( (ptr=fopen(filename, "w")) != NULL){
    
         puts("File Opened");
         return ptr;
         }
         else{
         puts("Error FILE NOT AVAILABLE");
         return NULL;
         }
    
    }
    

    geänderter Ausschnitt aus dbank.c

    void dbank(const char *fname, const int ct_dbank){
    
    struct data ibuffer, obuffer[5];     
    FILE *save, *open;
    int choose=0;
    int i, j, k;
    char dummy;
    
    while (choose != 3) {
    
    system("cls");
    puts("######################################");
    puts("#   Daten Eingeben oder Auslesen?    #");
    puts("#       1=  Eingeben                 #");
    puts("#       2=  Auslesen                 #");
    puts("#       3=  EXIT                     #");
    puts("######################################");
    puts("\n");
    scanf("%d",&choose);
    
    switch (choose){
    
           case input   :    fileopen_w(save, fname);
    
                             for (i=0; i< ct_dbank; i++) {
                                 fflush(stdin);
                                 puts("Enter Name: ");
                                 fgets(ibuffer.name, smax, stdin);
                                 puts("Enter ID: ");
                                 scanf("%d", &ibuffer.id);
                                 fflush(stdin);
                                 puts("Enter Status: ");
                                 scanf("%c", &ibuffer.status);
                                 fwrite(&ibuffer, sizeof(ibuffer), 1, save);
                                 } 
                                 fclose(save); 
                           break;
    


  • Du willst nicht das ändern, auf das save zeigt.
    Du willst save ändern. Darum musst du die Adresse von save übergeben.
    Das ergibt dann einen Doppelzeiger in fileopen_w.

    Lass FILE* als Paramter einfach weg.

    FILE* fileopen_w(const char* filename){
    
        FILE *ptr;
        if ( (ptr=fopen(filename, "w")) != NULL){
    
          puts("File Opened");
          return ptr;
        }
        else{
          puts("Error FILE NOT AVAILABLE");
          return NULL;
        }
    
    }
    
    ... 
    case input   :   save = fileopen_w(fname);
    

    Aber was passiert, wenn wirklich mal eine NULL zurück kommt.
    Du machst weiter als sei dies nie der Fall. Dann brauchst du auch nicht den Wrapper für fopen.



  • Aber was passiert, wenn wirklich mal eine NULL zurück kommt.
    Du machst weiter als sei dies nie der Fall. Dann brauchst du auch nicht den Wrapper für fopen.

    Ja, das muss ich noch machen. Das ganze ist noch sehr "Experimentell".

    Du willst save ändern. Darum musst du die Adresse von save übergeben.
    Das ergibt dann einen Doppelzeiger in fileopen_w.

    😮 😮 Ich dachte mir gestern noch "Wenigstens werd ich sowas wie Doppelzeiger bestimmt nie brauchen. Ähmm... ja.
    Ok, das würde mich aber jetzt brennend interessieren, da ich bis jetzt immer dachte "Doppelzeiger brauch ich nicht, weiß keine Anwendung dafür (Array ausgenommen)".

    Wie würde das mit dem Doppelzeiger dann funktionieren?



  • FILE* fileopen_w(FILE **ptr, const char* filename){
    
        if ( (*ptr=fopen(filename, "w")) != NULL){ // *ptr ist ein einfacher Zeiger
    
         puts("File Opened");
         return *ptr;
         }
         else{
         puts("Error FILE NOT AVAILABLE");
         return NULL;
         }
    
    }	
    ...
    case input   :    fileopen_w(&save, fname);  // du übergibst die Adresse von save
    


  • Danke!! Die funktion hatte ich schon hingebastelt,

    #include <stdio.h>
    #include <stdlib.h>
    #include "system.h"
    
    FILE* fileopen_r(FILE **ptr, const char* filename){ 
    
        if ( (*ptr=fopen(filename, "r")) != NULL){ 
    
         puts("File Opened"); 
         return *ptr; 
         } 
         else{ 
         puts("Error FILE NOT AVAILABLE"); 
         return NULL; 
         } 
    
    }
    

    Aber das ich dann beim Aufruf die Adresse übergeben muss.... Da wär ich nicht so schnell drauf gekommen. Danke nochmal.
    Muss mich mal mit der Doppelzeiger "Sache" etwas mehr beschäftigen 🙂


Anmelden zum Antworten