Risposte:
Secondo le specifiche, malloc (0) restituirà "un puntatore nullo o un puntatore univoco che può essere passato con successo a free ()".
Questo fondamentalmente non ti consente di allocare nulla, ma comunque di passare la variabile "artist" a una chiamata a free () senza preoccupazioni. Per scopi pratici, è più o meno come fare:
artist = NULL;
Lo standard C (C17 7.22.3 / 1) dice:
Se la dimensione dello spazio richiesto è zero, il comportamento è definito dall'implementazione: o viene restituito un puntatore nullo o il comportamento è come se la dimensione fosse un valore diverso da zero, tranne per il fatto che il puntatore restituito non deve essere utilizzato per accedere a un oggetto.
Quindi, malloc(0)
potrebbe restituire NULL
o un puntatore valido che potrebbe non essere dereferenziato . In entrambi i casi, è perfettamente valido chiamarefree()
.
Non penso davvero che malloc(0)
sia molto utile, tranne nei casi in cui malloc(n)
viene chiamato in un ciclo per esempio, en
potrebbe essere zero.
Guardando il codice nel link, credo che l'autore avesse due idee sbagliate:
malloc(0)
restituisce un puntatore valido sempre , efree(0)
è cattivo.Quindi, si è assicurato che quella artist
e altre variabili contenessero sempre un valore "valido". Il commento dice molto: // these must always point at malloc'd data
.
malloc(0)
restituito un puntatore valido, malloc()
restituire NULL
significa sempre "fallimento" e 0
non è più un caso speciale, il che è più coerente.
malloc
mancato ottenimento della memoria sono definite dall'implementazione, un'implementazione potrebbe semplicemente definire che le allocazioni di dimensione 0 sono sempre insoddisfacenti ( ENOMEM
), e ora malloc(0)
restituire 0 (con errno==ENOMEM
) è coerente. :-)
realloc
un puntatore restituito da malloc(0)
? Puoi realloc((char*)NULL)
?
Il comportamento di malloc (0) è specifico dell'implementazione. La libreria può restituire NULL o avere il normale comportamento malloc, senza memoria allocata. Qualunque cosa faccia, deve essere documentata da qualche parte.
Di solito, restituisce un puntatore valido e univoco ma NON deve essere dereferenziato. Notare inoltre che PU consumare memoria anche se in realtà non ha allocato nulla.
È possibile riallocare un puntatore malloc (0) non nullo.
Tuttavia, avere un malloc (0) verbatim non è molto utile. Viene utilizzato principalmente quando un'allocazione dinamica è zero byte e non ti importava di convalidarla.
malloc()
deve conservare le "informazioni di manutenzione" da qualche parte (questa dimensione del blocco allocato, ad esempio, e altri dati ausiliari). Quindi, se malloc(0)
non viene restituito NULL
, utilizzerà la memoria per memorizzare tali informazioni e, in caso contrario free()
, costituirà una perdita di memoria.
malloc()
restituirà, oppure restituire NULL
.
malloc(0)
. Tuttavia, nella stessa implementazione della libreria C standard, realloc(ptr, 0)
libera ptr
e restituisce NULL.
C'è una risposta altrove in questa pagina che inizia con "malloc (0) restituirà un indirizzo di memoria valido e il cui intervallo dipenderà dal tipo di puntatore a cui viene allocata la memoria". Questa affermazione non è corretta (non ho abbastanza reputazione per commentare direttamente quella risposta, quindi non posso inserire questo commento direttamente sotto).
L'esecuzione di malloc (0) non allocherà automaticamente la memoria della dimensione corretta. La funzione malloc non sa a cosa stai trasmettendo il risultato. La funzione malloc si basa esclusivamente sul numero di dimensione fornito come argomento. È necessario eseguire malloc (sizeof (int)) per ottenere spazio di archiviazione sufficiente per contenere un int, ad esempio, non 0.
malloc(0)
non ha alcun senso per me, a meno che il codice non si basi su un comportamento specifico dell'implementazione. Se il codice è pensato per essere portabile, deve tenere conto del fatto che un ritorno NULL da malloc(0)
non è un errore. Quindi, perché non assegnare artist
comunque NULL , dal momento che è un risultato di successo valido, è meno codice e non farà sì che i programmatori di manutenzione impieghino del tempo per capirlo?
malloc(SOME_CONSTANT_THAT_MIGHT_BE_ZERO)
o malloc(some_variable_which_might_be_zero)
forse potrebbero avere i loro usi, anche se ancora una volta devi fare molta attenzione a non trattare un ritorno NULL come un fallimento se il valore è 0, ma una dimensione 0 dovrebbe essere OK.
Ci sono molte risposte mezze vere qui intorno, quindi ecco i fatti concreti. La pagina di malloc()
manuale per dice:
Se la dimensione è 0, malloc () restituisce NULL o un valore di puntatore univoco che può essere successivamente passato con successo a free ().
Ciò significa che non vi è assolutamente alcuna garanzia che il risultato di malloc(0)
sia univoco o non NULL. L'unica garanzia è data dalla definizione di free()
, ancora una volta, ecco cosa dice la pagina di manuale:
Se ptr è NULL, non viene eseguita alcuna operazione.
Quindi, qualunque cosa malloc(0)
ritorni, può essere tranquillamente passata a free()
. Ma anche un NULL
puntatore può farlo .
Di conseguenza, la scrittura non artist = malloc(0);
è in alcun modo migliore della scrittura artist = NULL;
malloc(0)
potrebbe restituire, diciamo, 0x1, e free()
potrebbe avere un controllo in caso speciale di 0x1 proprio come ha fatto per 0x0.
NULL
o un puntatore univoco". invece "o un puntatore nullo o un puntatore allo spazio allocato". Non vi è alcun requisito univoco . OTOH, la restituzione di un valore speciale non univoco può interrompere il codice che conta su valori univoci. Forse una domanda d'angolo per SO.
man
può anche documentare la forma definita dall'implementazione usata in * nix. In questo caso non è così, ma non è ancora una fonte canonica per il generale C.
Perché non dovresti farlo ...
Poiché il valore restituito da malloc dipende dall'implementazione, potresti ricevere un puntatore NULL o un altro indirizzo. Questo può finire per creare overflow dell'heap-buffer se il codice di gestione degli errori non controlla sia la dimensione che il valore restituito, portando a problemi di stabilità (arresti anomali) o problemi di sicurezza anche peggiori.
Considera questo esempio, in cui un ulteriore accesso alla memoria tramite l'indirizzo restituito danneggerà l'heap se la dimensione è zero e l'implementazione restituisce un valore non NULL.
size_t size;
/* Initialize size, possibly by user-controlled input */
int *list = (int *)malloc(size);
if (list == NULL) {
/* Handle allocation error */
}
else {
/* Continue processing list */
}
Vedi questa pagina di codifica sicura dagli standard di codifica CERT dove ho preso l'esempio sopra per ulteriori letture.
Certo, non l'ho mai visto prima, questa è la prima volta che vedo questa sintassi, si potrebbe dire, un classico caso di overkill di funzioni. Insieme alla risposta di Reed, vorrei sottolineare che esiste una cosa simile, che appare come una funzione sovraccarica realloc
:
realloc(foo, size);
. Quando passi un puntatore non NULL e una dimensione pari a zero a realloc, realloc si comporta come se avessi chiamato free (...)realloc(foo, size);
,. Quando passi un puntatore NULL e la dimensione è diversa da zero, realloc si comporta come se avessi chiamato malloc (...)Spero che questo aiuti, Cordiali saluti, Tom.
malloc (0) restituirà NULL o un puntatore valido che può essere giustamente passato a free. E sebbene sembri che il ricordo a cui punta sia inutile o non possa essere scritto o letto, non è sempre vero. :)
int *i = malloc(0);
*i = 100;
printf("%d", *i);
Ci aspettiamo un errore di segmentazione qui, ma sorprendentemente, questo stampa 100! È perché malloc in realtà richiede un'enorme porzione di memoria quando chiamiamo malloc per la prima volta. Dopo ogni chiamata a malloc, utilizza la memoria di quel grosso pezzo. Solo dopo che quell'enorme pezzo è finito, viene richiesta nuova memoria.
Uso di malloc (0): se ti trovi in una situazione in cui vuoi che le successive chiamate malloc siano più veloci, chiamare malloc (0) dovrebbe farlo per te (eccetto per i casi limite).
*i
potrebbe non andare in crash nel tuo caso, ma è comunque un comportamento indefinito. Attenzione ai demoni nasali!
malloc(0)
questo non menzionato. Su quelle implementazioni in cui restituisce un valore diverso da NULL, specialmente in una build DEBUG, probabilmente alloca PIÙ di quanto richiesto e ti dà il puntatore appena oltre la sua intestazione interna. Ciò consente di avere un'idea dell'effettivo utilizzo della memoria se lo si ottiene prima e dopo una serie di allocazioni. eg: void* before = malloc(0); ... void* after = malloc(0); long long total = after - before;
o qualcosa di simile.
malloc(0)
. Potresti dire anche a quale capitolo ti riferisci? Sarebbe bello anche fornire una citazione esatta.
In Windows:
void *p = malloc(0);
allocherà un buffer di lunghezza zero sull'heap locale. Il puntatore restituito è un puntatore di heap valido.malloc
alla fine chiama HeapAlloc
utilizzando l'heap di runtime C predefinito che quindi chiama RtlAllocateHeap
, ecc.free(p);
utilizza HeapFree
per liberare il buffer di lunghezza 0 nell'heap. Non liberarlo comporterebbe una perdita di memoria.In realtà è abbastanza utile e (ovviamente IMHO), il comportamento consentito di restituire un puntatore NULL è rotto. Un puntatore dinamico è utile non solo per ciò a cui punta, ma anche per il fatto che il suo indirizzo è univoco. La restituzione di NULL rimuove quella seconda proprietà. Tutti i mallocs incorporati che programma (abbastanza frequentemente in effetti) hanno questo comportamento.
Non sono sicuro, secondo un codice sorgente malloc casuale che ho trovato, un input di 0 risulta in un valore di ritorno di NULL. Quindi è un modo folle di impostare il puntatore dell'artista su NULL.
http://www.raspberryginger.com/jbailey/minix/html/lib_2ansi_2malloc_8c-source.html
Ecco l'analisi dopo l'esecuzione con lo strumento di controllo della memoria valgrind.
==16740== Command: ./malloc0
==16740==
p1 = 0x5204040
==16740==
==16740== HEAP SUMMARY:
==16740== in use at exit: 0 bytes in 0 blocks
==16740== total heap usage: 2 allocs, 2 frees, 1,024 bytes allocated
==16740==
==16740== All heap blocks were freed -- no leaks are possible
ed ecco il mio codice di esempio:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
//int i;
char *p1;
p1 = (char *)malloc(0);
printf("p1 = %p\n", p1);
free(p1);
return 0;
}
Per impostazione predefinita, vengono allocati 1024 byte. Se aumento la dimensione di malloc, i byte allocati aumenteranno di 1025 e così via.
Secondo la risposta di Reed Copsey e la pagina man di malloc, ho scritto alcuni esempi da testare. E ho scoperto che malloc (0) gli darà sempre un valore unico. Guarda il mio esempio:
char *ptr;
if( (ptr = (char *) malloc(0)) == NULL )
puts("Got a null pointer");
else
puts("Got a valid pointer");
L'output sarà "Got a valid pointer", il che significa che ptr
non è nullo.
malloc(0)
restituirà un indirizzo di memoria valido e il cui intervallo dipenderà dal tipo di puntatore a cui viene allocata la memoria. Inoltre è possibile assegnare valori all'area di memoria, ma questo dovrebbe essere compreso nell'intervallo con il tipo di puntatore utilizzato. Puoi anche liberare la memoria allocata. Lo spiegherò con un esempio:
int *p=NULL;
p=(int *)malloc(0);
free(p);
Il codice sopra funzionerà bene in un gcc
compilatore su macchina Linux. Se si dispone di un compilatore a 32 bit, è possibile fornire valori nell'intervallo intero, ad esempio da -2147483648 a 2147483647. Lo stesso vale anche per i caratteri. Si noti che se il tipo di puntatore dichiarato viene modificato, l'intervallo di valori cambierà indipendentemente dal malloc
typecast, ad es
unsigned char *p=NULL;
p =(char *)malloc(0);
free(p);
p
prenderà un valore da 0 a 255 di char poiché è dichiarato un int senza segno.
malloc()
non sa nulla del cast (che in realtà è del tutto superfluente in C). Dereferenziare il valore restituito di malloc(0)
richiamerà un comportamento non definito.
Solo per correggere una falsa impressione qui:
artist = (char *) malloc(0);
non tornerà mai più NULL
; non è lo stesso di artist = NULL;
. Scrivi un semplice programma e confrontalo artist
con NULL
. if (artist == NULL)
è falso ed if (artist)
è vero.