2016-11-30 3 views
-5

ich Zeiger zu verstehen, ich versuche, und ich habe dieses einfache Beispiel bekamC char-Array, Zeiger, malloc, frei

void third(char ****msg) { 
    ***msg = malloc(5 * sizeof (char)); 
    printf("\nthe msg in third is :%s ", ***msg); 
    strcpy(***msg, "third"); 
    printf("\nthe msg in third after is: %s", ***msg); 
    // free(***msg); 
} 

void change(char***msg) { 
    **msg = malloc(5 * sizeof (char)); 
    printf("\nthe msg in change is :%s ", **msg); 
    strcpy(**msg, "change"); 
    printf("\nthe msg in change after is: %s", **msg); 
    third(&msg); 
    // free(**msg); 
} 

void test(char ** msg) { 
    *msg = malloc(5 * sizeof (char)); 
    printf("\n the msg in test is: %s", *msg); 

    strcpy(*msg, "test"); 
    printf("\nthe msg in test after is: %s\n", *msg); 

    change(&msg); 
    free(*msg); 
} 

int main(int argc, char** argv) { 

    char * msg; 
    test(&msg); 
    printf("\nthe msg back in main is: %s", msg); 
} 

Ich könnte sagen, es funktioniert gut, aber könnten Sie mir sagen, wann und wie ich muss den zugewiesenen Speicher freimachen, denn wenn ich die // aus Funktionen entferne und drittens laufe und es mache habe ich Fehler. Und es gibt einen Weg, um den Inhalt der Nachricht in der ersten print-Anweisung jeder Funktion zu erhalten - siehe otuput:

the msg in test is: 
the msg in test after is: test 
the msg in change is :0�� 
the msg in change after is: change 
the msg in third is :P�� 
the msg in third after is: third 
the msg back in main is: 

Gibt es eine Möglichkeit, die msg in Veränderung zu bekommen ist: Test und dann die msg in der dritten ist: Änderung

+0

Was "Fehler" sind Sie "Haben"? –

+7

einfaches Beispiel? mit vier Starts? Du bist weit mehr als ein t (h) ree-star Programmierer zu werden. –

+2

WOW! Du bist der erste 4-Sterne-C-Programmierer, den ich sehe! Sie sind sich bewusst, ein 3-Sterne-C-Programmierer ist schon kein Kompliment, oder? – Olaf

Antwort

2

Vergessen Sie über das Programm, da mit ihm einfach zu viel los ist:

  • Sie nicht mehrere Dereferenzierungsebenen benötigen. Zwei Ebenen sind genug. Übergeben Sie den Zeiger an den Zeiger einfach an die nächste Funktion, wenn diese Funktion die Adresse ändern muss.
  • Sie versuchen, die Zeichenfolge zu drucken, bevor sie initialisiert wurde.
  • Sie versuchen, die Zeichenfolge nach dem Freigeben zu verwenden.
  • Sie erstellen Speicherverluste, indem Sie malloc wiederholt aufrufen, ohne die alten Inhalte zu bereinigen. Verwenden Sie stattdessen realloc.
  • Sie weisen falsche Speichermengen zu, sodass die Arrays nicht groß genug sind, um die Strings aufzunehmen, die Sie hineingezählt haben. Beachten Sie außerdem, dass Sie genügend Platz für den Nullabschluss zuweisen müssen.

Und so weiter. Hier ist eine feste Version:

#include <stdlib.h> 
#include <string.h> 
#include <stdio.h> 

void third(char** msg) { 
    const char str[] = "third"; 

    *msg = realloc(*msg, sizeof(str)); 
    printf("the msg in third is :%s\n", *msg); 

    strcpy(*msg, str); 
    printf("the msg in third after is: %s\n", *msg); 
} 

void change(char** msg) { 
    const char str[] = "change"; 

    *msg = realloc(*msg, sizeof(str)); 
    printf("the msg in change is :%s\n", *msg); 

    strcpy(*msg, str); 
    printf("the msg in change after is: %s\n", *msg); 

    third(msg); 
} 

void test(char** msg) { 
    const char str[] = "test"; 

    *msg = malloc(sizeof(str)); 
    printf("the msg in test is just garabage at this point, no need to print it.\n"); 

    strcpy(*msg, str); 
    printf("the msg in test after is: %s\n", *msg); 

    change(msg); 
} 

int main(int argc, char** argv) { 

    char* msg; 
    test(&msg); 
    printf("the msg back in main is: %s\n", msg); 

    free(msg); 
} 
+0

Nun verstehe ich das. Gilt das für andere Datentypen zB int oder int []? –

+0

@JohnRichards Der Datentyp des Arrays spielt keine Rolle, aber char Arrays, die als Strings verwendet werden, sind ein Sonderfall Sie müssen null terminiert sein.Wenn Sie 'const char str [] =" test "deklarieren;' erhalten Sie ein Array von 4 Zeichen + 1 Null-Terminator. Deshalb funktioniert 'sizeof (str)'. – Lundin

1

Im wirklichen Leben vermeiden Sie so viel "Stern" (dh die Zahl der Indirektion). Auch Ihr Code hat mehrere Ausgabe undefined behavior (UB)

void third(char ****msg) { 
    ***msg = malloc(5 * sizeof (char)); 
    printf("\nthe msg in third is :%s ", ***msg);// Don't do that, ***msg is not intialize => UB 
    strcpy(***msg, "third"); // Don't do that => ***msg has 5 bytes, and you copy 6 char => UB 
    printf("\nthe msg in third after is: %s", ***msg); 
    // free(***msg); 
} 

void change(char***msg) { 
    **msg = malloc(5 * sizeof (char)); 
    printf("\nthe msg in change is :%s ", **msg);// Don't do that, **msg is not intialize => UB 
    strcpy(**msg, "change"); // Don't do that => **msg has 5 bytes, and you copy 7 char => UB 
    printf("\nthe msg in change after is: %s", **msg); 
    third(&msg); 
    // free(**msg); 
} 

void test(char ** msg) { 
    *msg = malloc(5 * sizeof (char)); 
    printf("\n the msg in test is: %s", *msg); // Don't do that, *msg is not intialize => UB 

    strcpy(*msg, "test"); 
    printf("\nthe msg in test after is: %s\n", *msg); 

    change(&msg); 
    free(*msg); 
} 

int main(int argc, char** argv) { 

    char * msg; 
    test(&msg); 
    printf("\nthe msg back in main is: %s", msg); //UB => you use freed variable 
} 

Nach Korrektur diese mehrere Quellen von UB beteiligt, es immer noch eine schlechte Design: Verwendung von free Funktion

Nach Tatsache, dass Sie Zeiger des Zeigers verwenden ... wenn Sie tun eine malloc innerhalb einer Funktion, Sie ändern auch Zeiger des Aufrufers. Versuchen Sie führen dies und sehen:

void first(char **t) 
{ 
    *t = malloc(5*sizeof(char)); 
} 

int main(int argc, char * argv[]) 
{ 
    char * t = NULL; 
    printf("%p\n", t); 
    first(&t); 
    printf("%p\n", t); 
    return 0; 
} 

es (demo) produzieren:

(nil) 
0x995f008 (or another address) 

Also, wenn Sie frei in test Sie kostenlos zugewiesenen Speicher in third


Schließlich Wie bereits im Kommentar erwähnt, genügen nur 2 Sterne:

void third(char **msg) { 
    free(*msg); // Free before allocate and change address stored in pointer 
    *msg = malloc(6 * sizeof (char)); 
    strcpy(*msg, "third"); 
    printf("\nthe msg in third after is: %s", *msg); 
} 

void change(char **msg) { 
    free(*msg); // Free before allocate and change address stored in pointer 
    *msg = malloc(7 * sizeof (char)); 
    strcpy(*msg, "change"); 
    printf("\nthe msg in change after is: %s", *msg); 
    third(msg); 
} 

void test(char ** msg) { 
    *msg = malloc(5 * sizeof (char)); 

    strcpy(*msg, "test"); 
    printf("\nthe msg in test after is: %s\n", *msg); 

    change(msg); 
} 

int main(int argc, char** argv) { 

    char * msg; 
    test(&msg); 
    printf("\nthe msg back in main is: %s", msg); 
    free(msg); // Deallocate memory ONLY when you don't need it anymore 
    msg = NULL; // Good practice, set to NULL freed pointer to inform that no more memory are allocated 
} 
+0

Okay, ich verstehe. Dann was ist mit Freigeben der Speicher. Ist die kostenlose im Test genug? –

+0

@JohnRichards Ich denke, meine Bearbeitung antwortet Ihre Frage – Garf365