domande newbie su malloc e sizeof

Qualcuno può spiegarmi perché la mia chiamata a malloc con una stringa di 6 dimensioni restituisce una dimensione di 4 byte? In effetti, qualsiasi argomento intero che do a malloc ottengo una dimensione di 4. Successivamente, sto provando a copiare due stringhe. Perché la mia copia della stringa copiata (NULL) è mia? Di seguito è riportato il mio codice:

int main() { char * str = "string"; char * copy = malloc(sizeof(str) + 1); printf("bytes allocated for copy: %d\n", sizeof(copy)); while(*str != '\0'){ *copy = *str; str++; copy++; } copy = '\0'; printf("%s\n", copy); } 

sizeof(str) restituisce la dimensione di un puntatore di tipo char* . Quello che dovresti fare è di malloc la dimensione della stringa stessa:

 char * copy = malloc(strlen(str) + 1); 

Inoltre, queste righe:

 while(*str != '\0'){ *copy = *str; str++; copy++; } copy = '\0'; 

Può essere riscritto facilmente in C come questo:

 while(*copy++ = *str++); 

Per prima cosa dovresti capire che sizeof (xxx) dove xxx è qualsiasi espressione di valore a sinistra (una variabile) è sempre equivalente a fare sizeof ( tipo di xxx ). Quindi ciò che sta realmente facendo il tuo sizeof (str) sta restituendo la dimensione di un char *, che è la dimensione di qualsiasi altro puntatore. Su un’architettura a 32 bit ne avrai 4, su un’architettura a 64 bit sarà 8, ecc.

Quindi, come hanno spiegato anche gli altri, è necessario conoscere la lunghezza della stringa che si desidera allocare, quindi aggiungere 1 per memorizzare il terminale \ 0, C implicitamente da usare alla fine delle stringhe.

Ma per fare quello che vuoi (copiare una stringa e allocare lo spazio necessario) sarà più semplice e più efficiente usare strdup , che fa esattamente questo: un malloc e una strcopy .

Non dovresti inoltre dimenticare di liberare spazio che ti sei assegnato (usando malloc, calloc, strdup o qualsiasi altra funzione di allocazione). In C non andrà via quando la variabile allocata andrà fuori campo. Rimarrà usato fino alla fine del programma. Questo è ciò che chiami una perdita di memoria.

 #include  /* for strdup, strlen */ #include  /* for printf */ int main() { char * str = "string"; char * copy = strdup(str); printf("bytes at least allocated for copy: %d\n", strlen(copy)+1); printf("%s\n", copy); free(copy); } 

Un ultimo punto: ho modificato il messaggio in byte almeno allocati perché non si conosce realmente la dimensione allocata quando si chiama malloc. Assegna abbastanza spesso uno spazio leggermente più che quello che hai chiesto. Una ragione è che in molti gestori di memoria i blocchi liberi sono collegati tra loro usando una struttura dati nascosta e qualsiasi blocco assegnato dovrebbe essere in grado di contenere almeno tale struttura, un altro è che i blocchi allocati sono sempre allineati in modo tale da essere compatibili con qualsiasi tipo allineamento.

Spero che ti possa aiutare a capire meglio C.

Stai ottenendo la dimensione del puntatore str (4 byte), non a cosa sta puntando?

sizeof(str) restituisce lo spazio necessario per memorizzare il puntatore alla stringa, non la stringa stessa. Ad esempio, puoi vedere la dimensione della stringa con strlen(str) .

Quindi modifichi il puntatore di copy su un numero intero che ha il valore 0 (il carattere '\0' ). È lo stesso di copy = NULL , che è quello che ti mostra la funzione printf ().

Per affrontare le tue seconde domande, eseguendo l’istruzione copy++ hai cambiato il valore della copy (ovvero, l’indirizzo in memoria che contiene un array di char ) in modo che al momento della stampa, sia puntato alla fine del array piuttosto che all’inizio (il valore restituito da malloc() ). Avrai bisogno di una variabile extra per aggiornare la stringa e poter accedere all’inizio della stringa:

Modifica per riparare malloc/sizeof issue – grazie CL.

 char * str = "string"; /* char * copy = malloc(sizeof(str) + 1); Oops */ char * copy = malloc(strlen(str) + 1); char * original_copy = copy; printf("bytes allocated for copy: %d\n", sizeof(copy)); while(*str != '\0'){ *copy = *str; str++; copy++; } copy = '\0'; printf("%s\n", original_copy); 

sizeof () restituisce la dimensione del tipo effettivo della variabile. Quindi, quando definisci il tuo tipo come char *, restituisce la dimensione di un puntatore.

Ma se hai reso la tua variabile una matrice, sizeof restituirebbe la dimensione della matrice stessa, cosa che farebbe ciò che vuoi fare:

 char *ptr = "moo to you"; char arr[] = "moo to you"; assert(sizeof(ptr) == 4); // assuming 32 bit assert(sizeof(arr) == 11); // sizeof array includes terminating NUL assert(strlen(arr) == 10); // strlen does not include terminating NUL 
  • sizeof () restituisce la dimensione del puntatore e non la quantità di byte allocati. Non è necessario contare i byte allocati, basta controllare se il puntatore restituito non è NULL .
  • La riga copy = '\0' ; ripristina il puntatore e lo rende NULL .

Puoi usare:

size_t malloc_usable_size (void * ptr);

invece di: sizeof

Ma restituisce la dimensione reale del blocco di memoria assegnato! Non le dimensioni che hai passato a malloc!