2011-12-22 17 views
21

Zastanawiałem się, dlaczego kod następujące isnt't pracyprzydzielić pamięci i zapisać ciąg w C

int main(int argc, char **argv) 
{ 
    char *test = (char*) malloc(12*sizeof(char)); 
    test = "testingonly"; 
    free(test); 
} 

Po myślenie o nim moje założenie, że pierwszy i przydzielić miejsca dla 12 znaków w pamięci, ale zadania w następna linia tworzy tablicę znaków na stosie, a jej adres pamięci jest przekazywany do przetestowania. Tak więc free() próbuje zwolnić miejsce na stosie, które nie jest dozwolone. Czy to jest poprawne?

Jakie byłoby właściwe podejście do zapisywania ciągu na stercie? Czy następujące sposoby są powszechne?

int main(int argc, char **argv) 
{ 
    char *test = (char*) malloc(12*sizeof(char)); 
    strcpy(test, "testingonly"); 
    free(test); 
} 
+4

Pierwsze rozwiązanie ilustruje klasyczne wyciek pamięci; otrzymujesz wskaźnik do pamięci przydzielonej, a następnie tracisz jedyne odwołanie do niej, gdy przypisujesz wskaźnik do literału ciągu do 'testu'. Po tym czasie nie ma uzasadnionego sposobu odniesienia się do przydzielonej pamięci - wycieku. –

+2

Nigdy nie wypisuj wyniku malloc w C, nie ma sensu i ukrywa tylko błędy i ostrzeżenia kompilatora. – Lundin

+2

tak - użyj 'strcpy' lub' strncpy' lub 'memcpy'. strncpy jest lepszy niż strcpy, ponieważ pomaga uniknąć problemu z przepełnieniem bufora podczas kopiowania przy maksymalnej liczbie N znaków. –

Odpowiedz

8

Już odpowiedziałeś na swoje pytanie. Zasadniczo, strcpy jest właściwym sposobem kopiowania napisów.

+0

Dopóki wiesz, że odpowiednia pamięć została już przydzielona w docelowym łańcuchu, a oba łańcuchy mają wartość NUL zakończoną. – Dave

5

Pierwsza wersja nie tworzy ciągu na stosie, ale masz rację, że nie masz pozwolenia na free go po przypisaniu. Literały łańcuchowe są zwykle przechowywane w stałych/tylko do odczytu sekcjach pamięci. Przypisanie niczego nie kopiuje, tylko sprawia, że ​​test wskazuje ten obszar pamięci. Nie możesz go uwolnić. Nie możesz także modyfikować tego ciągu.

Twój drugi fragment kodu jest prawidłowy i zwykle. Możesz również zajrzeć do strdup, jeśli twoja implementacja to ma.

+0

+1 dla sekcji stałych/tylko do odczytu –

+0

'strncpy' to * nie * bezpieczniejsza wersja' strcpy'. Może pozostawić docelową tablicę bez końca. Bardzo rzadko jest to właściwe rozwiązanie. –

+0

@Keith: right, usunięto odniesienie do tego. 'strdup' jest jednak całkiem niezły (zakładając, że wiesz, że twój wkład to 1. poprawny ciąg C i 2. akceptowalny rozmiar - cokolwiek to jest dla twojej aplikacji). – Mat

4

Cóż, masz rację. Teraz przeanalizujmy pierwszy fragment kodu.

char *test = (char*) malloc(12*sizeof(char)); 

Powyższy kod nie stanowi problemu.

test = "testingonly"; 

Tutaj zmodyfikowany wskaźnik test prowadzącej do wycieku pamięci. A kiedy próbujesz uwolnić, nie zwalniasz faktycznego przydzielonego wskaźnika, ale jeden "literujący" literalnie wskazuje na. Literał wskazuje na stałą pamięć, której nie można przesłonić w zwykłych scenariuszach.

Teraz, gdy chodzi o drugi fragment kodu, będzie to działało dobrze podczas jawnego kopiowania danych z miejsca, w którym literał znajduje się na stercie, na którym wskazuje twój test.

Do twojego drugiego punktu tak strcpy to zwykły sposób. Inne sposoby to "memcpy", jeśli kopiujesz surowe bajty.

UWAGA: Literały nie są przechowywane na stosie. Ale nie można modyfikować lokalizacji, w której przechowywane są literały.

+0

+1 dla "to zadziała dobrze, gdy jawnie skopiowano dane z miejsca, w którym literał znajduje się na stercie, na którym wskazuje Twój test". –

57
char *test = (char*) malloc(12*sizeof(char)); 

     +-+-+-+-+-+-+-+-+-+-+-+-+ 
test--->|x|x|x|x|x|x|x|x|x|x|x|x| (uninitialized memory, heap) 
     +-+-+-+-+-+-+-+-+-+-+-+-+ 

test = "testingonly"; 

     +-+-+-+-+-+-+-+-+-+-+-+-+ 
test + |x|x|x|x|x|x|x|x|x|x|x|x| 
    | +-+-+-+-+-+-+-+-+-+-+-+-+ 
    | +-+-+-+-+-+-+-+-+-+-+-+-+ 
    +->|t|e|s|t|i|n|g|o|n|l|y|0| 
     +-+-+-+-+-+-+-+-+-+-+-+-+ 

free(test); // error, because test is no longer pointing to allocated space. 

Zamiast zmieniać wskaźnik test, trzeba skopiować ciąg "testingonly" w miejscu wydzielonym na przykład przy użyciu strcpy lub użyj strdup. Zwróć uwagę, że funkcje takie jak malloc i strdup zwróci NULL, jeśli dostępna jest niewystarczająca ilość pamięci, a zatem powinny być sprawdzone.

char *test = (char*) malloc(12*sizeof(char)); 
strcpy(test, "testingonly"); 

     +-+-+-+-+-+-+-+-+-+-+-+-+ 
test--->|t|e|s|t|i|n|g|o|n|l|y|0| 
     +-+-+-+-+-+-+-+-+-+-+-+-+ 

lub

char *test = strdup("testingonly"); 

     +-+-+-+-+-+-+-+-+-+-+-+-+ 
test--->|t|e|s|t|i|n|g|o|n|l|y|0| 
     +-+-+-+-+-+-+-+-+-+-+-+-+ 
+4

+ doceń wysiłek włożony w jego wyjaśnienie. – dicaprio

+0

dziękuję !!!! wspaniały –

0

kod

#include <stdio.h> 
int main(int argc, char **argv) 
{ 
    char *test = (char*) malloc(12*sizeof(char)); 
    strcpy(test, "testingonly"); 
    printf("string is: %s\n",test); 
    free(test); 
    return 0; 
} 

zadziała

0

To dla alokacji pamięci:

char *string; 
string = (char *) malloc(15); 

to służy do zapisywania danych:

strcpy(str, "kavitajain"); 
printf("String = %s, Address = %u\n", str, str); 
Powiązane problemy