Sono molto confuso su malloc() e calloc() in C

Ho sempre programmato in Java, che è probabilmente il motivo per cui sono così confusa su questo:

In Java dichiaro un puntatore:

int[] array

e inizializzare o assegnare un po ‘ di memoria:

int[] array = {0,1,0}
int[] array = new int[3]

Ora, in C, è tutto così confuso. In un primo momento ho pensato che fosse facile come la dichiarazione:

int array[]

e l’inizializzazione o l’assegnazione di un po ‘ di memoria:

int array[] = {0,1,0}
int array[] = malloc(3*sizeof(int))
int array[] = calloc(3,sizeof(int))

A meno che non mi sono sbagliato, tutto quanto sopra è equivalente Java-C, giusto?

Allora, oggi ho incontrato un codice che ho trovato il seguente:

pthread_t tid[MAX_OPS];

e alcune righe di seguito, senza alcun tipo di inizializzazione…

pthread_create(&tid[0],NULL,mou_usuari,(void *) 0);

Sorprendentemente (almeno per me), il codice funziona! Almeno in Java, che restituisce un bel “NullPointerException”!

Così, nell’ordine:

  1. Sono corretto con tutti i Java-C “traduzioni”?
  2. Perché non è che il codice del lavoro?
  3. C’è qualche differenza tra l’utilizzo di malloc(n*sizeof(int)) e calloc(n,sizeof(int))?

Grazie in anticipo

InformationsquelleAutor bluehallu | 2010-11-21

 

5 Replies
  1. 38

    Non è possibile assegnare la memoria per un array. Un array di dimensione fissa, per l’intera sua durata. Un array può mai essere nullo. Un array non è un puntatore.

    malloc restituisce l’indirizzo di un blocco di memoria riservata per il programma. Non si può “cedere” che (essendo il blocco di memoria) di un array, ma è possibile memorizzare l’indirizzo di questo blocco di memoria in un puntatore: per fortuna, array di sottoscrizione è definito tramite puntatori, così si può “usare i puntatori come” matrici, ad esempio,

    int *ptr = malloc(5 * sizeof *ptr);
    ptr[2] = 5; //access the third element "of ptr"
    free(ptr); //always free at the end

    Quando si dichiara un array senza una dimensione (cioè array[]), significa semplicemente la dimensione della matrice è determinata dalla lista di inizializzazione. Che è

    int array[] = {1, 2, 3, 4, 5}; //is equal to
    int array[5] = {1, 2, 3, 4, 5};

    Tentando di dichiarare un array senza dimensione e senza un inizializzatore è un errore.


    Il codice pthread_t tid[MAX_OPS]; dichiara un array di nome tid di tipo pthread_t e di dimensioni MAX_OPS.

    Se l’array di memorizzazione automatica (ovvero dichiarazione all’interno di una funzione e non statico, non globale), ciascuna delle matrici degli elementi di valore indeterminato (e potrebbe causare un comportamento indefinito, cercando di leggere tale valore). Per fortuna, tutto ciò che la chiamata di funzione è l’indirizzo del primo elemento dell’array come primo parametro, e probabilmente inizializza (l’elemento) all’interno della funzione.


    La differenza di calloc e malloc è che il blocco di memoria che calloc restituisce inizializzata a zero. Che è;

    int *ptr = calloc(5, sizeof *ptr);
    //is somewhat equal to
    int *ptr = malloc(5 * sizeof *ptr);
    memset(ptr, 0, 5 * sizeof *ptr);

    La differenza tra

    int *ptr = malloc(5 * sizeof *ptr);
    //and
    int array[5];

    è che array ha memorizzazione automatica, (è memorizzato nello stack), ed è “uscito” dopo va fuori del campo di applicazione. ptr, tuttavia, (è memorizzato su heap), è allocata in modo dinamico e deve essere freed dal programmatore.

    • Il comma 1 ha alcuni pericolosamente ambigue affermazioni. L’OP non stava cercando di assegnare la memoria per un array, egli è stato il tentativo di assegnare un (void *), il ritorno da malloc() per una matrice, e se la matrice fosse stato un int *Array[i], probabilmente per{} loop, funziona bene, ed è la base per il modo dinamico, le matrici multidimensionali sono allocate fuori heap. Inoltre, C99 supporti di dimensioni variabili array allocato fuori la pila, una caratteristica che pochi programmatori C utilizzare, la maggior parte preferendo alloca(), me compreso. stackoverflow.com/q/1018853/2548100
    • calloc() è praticamente solo memset(malloc(n * mysize),0, (n * mysize)). Soprattutto perché C utilizza stringhe con terminazione null, calloc() è molto utile, soprattutto durante la visualizzazione di stringhe in un debugger, che di solito mostra la stringa solo fino al valore nullo di terminazione. Se sei solo indicando con C, utilizzare calloc invece di malloc, che vi salverà da un sacco di non-terminato C string errori che si possono e probabilmente si andrà in crash il programma. Per la produzione/codice di sblocco, utilizzare calloc() solo quando è effettivamente necessario per inizializzare il buffer/matrice/vettore (_int8) 0.
    • Solo per avvolgere le cose, e per completezza, un Array È un puntatore. In realtà, il nome di array in C è esattamente, precisamente un puntatore alla base del primo byte del 1 ° oggetto dell’array, e niente di più. Per le persone provenienti da Java .Net, ecc, è utile sapere che C tiene il tipo di oggetti/variabili completamente separata dall’archiviazione allocato per tenerli. Questo è il motivo per cui si può lanciare un puntatore a int, creare organizzazioni Sindacali, ecc. Molto, molto flessibile, ma pericoloso per noobies. Quando si assegna una matrice di int, il suo solo di archiviazione in una posizione. Si può mettere tutto quello che ti piace in quel deposito.
    • Molto bella risposta.
  2. 4

    Mancano tre molto di base e stringere (e fuorviante!) C argomenti:

    • la differenza tra array e puntatori
    • la differenza tra statico e dinamico di allocazione
    • la differenza di dichiarare variabili nello stack o sul mucchio

    Se si scrive int array[] = malloc(3*sizeof(int)); si otterrebbe un errore di compilazione (qualcosa come “identifier”: inizializzazione di matrice esigenze parentesi graffe).

    Questo significa che la dichiarazione di un array consente solo di inizializzazione statica:

    • int array[] = {1,2,3}; che si riserva 3 contigui interi stack;
    • int array[3] = {1,2,3}; che è la stessa della precedente;
    • int array[3]; che ancora riserve 3 contigui interi stack, ma non inizializza (il contenuto sarà casuale spazzatura)
    • int array[4] = {1,2,3}; quando la lista di inizializzazione non inizializzare tutti gli elementi, il resto sono impostati a 0 (C99 §6.7.8/19): in questo caso si otterrà 1,2,3,0

    Nota che in tutti questi casi non si assegnazione nuova memoria, si utilizzano solo la memoria già impegnata a pila. Si esegue in un problema solo se lo stack è pieno (credo, sarebbe un di overflow dello stack). Per questo motivo dichiara int array[]; sarebbe sbagliato e senza senso.

    Utilizzare malloc dichiarare un puntatore: int* array.

    Quando si scrive int* array = malloc(3*sizeof(int)); si sta effettivamente facendo tre operazioni:

    1. int* array dice al compilatore di prenotare un puntatore allo stack (un numero intero variabile che contiene un indirizzo di memoria)
    2. malloc(3*sizeof(int)) alloca su heap 3 contigue di numeri interi e restituisce l’indirizzo del primo
    3. = assegna le copie che il valore di ritorno (l’indirizzo del primo numero intero che avete assegnato) al puntatore variabile

    Quindi, per tornare alla tua domanda:

    pthread_t tid[MAX_OPS];

    è un array in pila, quindi non ha bisogno di essere allocato (se MAX_OPS è, diciamo, 16 allora lo stack sarà riservato il numero di byte contigui necessari per adattarsi a 16 pthread_t). Il contenuto di questa memoria sarà garbage collection (stack variabili non inizializzate a zero), ma pthread_create restituisce un valore nel primo parametro un puntatore a un pthread_t variabile) e ignora qualsiasi contenuto precedente, in modo che il codice è solo bene.

    • per il int array[4], sono tutti inizializzato. Quando la lista di inizializzazione non inizializzare tutti gli elementi, il resto sono impostati a 0/NULL (C99 §6.7.8/19).
    • Questo è fonte di confusione; “mucchio” e “allocazione dinamica” si riferiscono alla stessa cosa. “inizializzazione statica” si intende l’inizializzazione di variabili statiche, che non è il caso quando si parla di cosiddetta “pila” di variabili. Il tipo di allocazione in int array[3]; all’interno di una funzione , è “allocazione automatica” (o “stack” informalmente, alcuni sistemi non hanno una pila), non “statico”.
  3. 1

    C offre statico di allocazione di memoria così come dinamico, è possibile allocare array dallo stack o in memoria eseguibile (gestita dal compilatore). Questo è lo stesso come in Java, è possibile allocare un int in pila o un Intero sul mucchio. Gli array in C sono proprio come qualsiasi altro stack variabile andare fuori del campo di applicazione, etc. In C99 essi possono anche avere una dimensione variabile, anche se non può essere ridimensionata.

    La differenza principale tra {} e malloc/calloc che a {} array allocati staticamente (non è necessario liberare) e inizializzate automaticamente per voi, considerando che la malloc/calloc array deve essere liberata in modo esplicito e devi inizializzare esplicitamente. Ma, naturalmente, malloc/calloc matrici di non andare fuori del campo di applicazione e si può (a volte) realloc() li.

    • Le matrici sono solo statico se al di fuori di qualsiasi funzione o esplicitamente segnalati static; altrimenti sono automatici
  4. 0

    2 – Questa dichiarazione array statico :

    pthread_t tid[MAX_OPS];

    Non abbiamo bisogno di allocare un blocco di memoria, invece di allocazione dinamica :

    pthread_t *tid = (pthread_t *)malloc( MAX_OPS * sizeof(pthread_t) );

    Non dimenticate di liberare la memoria :

    free(tid);

    3 – La differenza tra malloc e calloc è calloc allocare un blocco di memoria per un array e inizializza tutti i bit a 0.

    • Quindi, quale sarebbe la differenza tra il primo e il secondo? E perché sei casting per un puntatore seconda riga? Scusate se sembro stupido, ma questo è tutto nuovo per me…
    • Ok, ho appena visto perché casting. Ancora, c’è qualche differenza pratica tra la prima e la seconda linea a parte che si può “spostare” il puntatore a tutto ciò che si desidera?
    • Una dichiarazione statica è più sicuro di una dinamica, ma non è possibile riallocare il blocco di memoria per cambiare la sua dimensione.
    • Il malloc call è sbagliato. Malloc prende un numero di byte non le voci.
    • Hai dimenticato di moltiplicare MAX_OPS da sizeof *tid in malloc().
    • Hai ragione. Ho corretto il mio errore.

  5. -1

    Utile quando si programma in C (rispetto a C++) per indicare *array in modo esplicito, per ricordare che c’è un puntatore che può essere spostato. Quindi vorrei iniziare da riformulare il tuo esempio come:

    int array[] = {0,1,2};
    int *array = malloc(3*sizeof(int));
    int *array = calloc(3,sizeof(int));

    Il primo rende chiaro che c’è qualcosa chiamato vettore che punta ad un blocco di memoria che contiene un 0, 1 e 2. array non possono essere spostati elesewhere.

    Il seguente codice:
    pthread_t tid[MAX_OPS];

    Infatti, causa un array con sizeof(pthread_t) * MAX_OPS essere assegnata. Ma non assegnare un puntatore chiamato *tid. C’è un indirizzo base dell’array, ma non è possibile spostarlo altrove.

    Il ptherad_t tipo è in realtà una copertura per un puntatore. Così tid sopra è in realtà un array di puntatori. E sono tutti allocati staticamente, ma non sono inizializzati.

    Il pthread_create prende la posizione all’inizio dell’array (&tid[0]), che è un puntatore, e alloca un blocco di memoria per contenere i pthread struttura di dati. Il puntatore è impostato a punto per la nuova struttura di dati e la struttura dei dati è allocato.

    L’ultima domanda, – – – la differenza tra malloc(n*sizeof(int)) e calloc(n,sizeof(int)) è che la inizializza ogni byte di 0, mentre il primo non.

    • Quindi, se io dichiaro: int array[] ha memoria già allocata? È poi lo stesso di dichiarare il puntatore e poi usando malloc? grazie ancora
    • No, non è la stessa cosa. int array[size] è assegnato dallo stack. int array[] = malloc() è sul mucchio.
    • In C, la prima di quelle 3 righe è semplicemente non valido. Esso non può essere compilato.
    • La prima riga non è valido.
    • Yep. Hai ragione. La prima riga non è valido.

Lascia un commento