[RISOLTO]array di char in C
Ho un piccolo dubbio riguardo gli array di char in C. Quando mi viene chiesto di creare una struttura che contenga una stringa di massimo, per esempio, 500 caratteri, io faccio (come tutti credo) un array di char. La questione è: nella dichiarazione dovrò scrivere array[500] o array[501]?
Cioè per essere precisi non si dovrebbe aggiungere 1 alla dimensione massima per contare anche il carattere terminatore di stringa '\0'? Oppure lo spazio per '\0' viene in qualche modo già messo in conto? (anche se in ogni caso non credo che per un solo carattere ci possano essere problemi...)
Grazie dell'aiuto!
Cioè per essere precisi non si dovrebbe aggiungere 1 alla dimensione massima per contare anche il carattere terminatore di stringa '\0'? Oppure lo spazio per '\0' viene in qualche modo già messo in conto? (anche se in ogni caso non credo che per un solo carattere ci possano essere problemi...)
Grazie dell'aiuto!

Risposte
Se vuoi allocare stringhe compatibili con string.h devi aggiungere anche il fine stringa. Se allocchi 500 char la massima lunghezza utile delle stringhe sarà 499, considerando che un char ti serve per '\0'.
array[N] significa un array lungo esattamente N caratteri, cioè le posizioni da 0 a N-1 sono occupabili, l'N-esima non appartiene all'array.
Quindi se l'array deve contenere al massimo N caratteri "visibili", devi anche aggiungere il carattere per il null byte finale ('\0'), se invece la vostra convenzione è quella di considerare nel conteggio anche il null byte allora non devi aggiungere 1 alla dimensione. Dipende, diciamo...
Il null byte finale _non_ viene aggiunto da solo, anzi, proprio questo è causa di problemi di sicurezza non da poco... Un carattere fa la differenza eccome, specialmente se si tratta del null byte! In una stringa va sempre considerato e bisogna sempre assicurarsi che questo sia presente.
Quindi se l'array deve contenere al massimo N caratteri "visibili", devi anche aggiungere il carattere per il null byte finale ('\0'), se invece la vostra convenzione è quella di considerare nel conteggio anche il null byte allora non devi aggiungere 1 alla dimensione. Dipende, diciamo...
Il null byte finale _non_ viene aggiunto da solo, anzi, proprio questo è causa di problemi di sicurezza non da poco... Un carattere fa la differenza eccome, specialmente se si tratta del null byte! In una stringa va sempre considerato e bisogna sempre assicurarsi che questo sia presente.
Grazie mille per i chiarimenti. Approfitto della discussione per chiarire un altro dubbio, per cui non vredo ci sia bisogno di aprire una discussione:
Quando uso la realloc (sempre in C), quello che faccio è modificare la dimensione di una zona di memoria allocata dinamicamente salvandomi i valori già contenuti (se espando un array di 10 elementi che ho già riempito, le informazioni mi rimangono). Realloc dovrebbe (se non erro) restituire un puntatore al primo elemento del nuovo array ridimensionato, ma a questo punto mi chiedevo se il nuovo array si costruisse "sopra" quello vecchio, o fosse una copia in un' altra parte della memoria.Cioè, posso fare:
ptr=malloc(.....);
ptr=(ptr,n);
senza preoccuparmi di garbage, perchè tanto sovrascrivo l'array, oppure devo fare tipo:
ptr=malloc(.....);
ptr1=realloc(ptr,n);
free(ptr);
Quando uso la realloc (sempre in C), quello che faccio è modificare la dimensione di una zona di memoria allocata dinamicamente salvandomi i valori già contenuti (se espando un array di 10 elementi che ho già riempito, le informazioni mi rimangono). Realloc dovrebbe (se non erro) restituire un puntatore al primo elemento del nuovo array ridimensionato, ma a questo punto mi chiedevo se il nuovo array si costruisse "sopra" quello vecchio, o fosse una copia in un' altra parte della memoria.Cioè, posso fare:
ptr=malloc(.....);
ptr=(ptr,n);
senza preoccuparmi di garbage, perchè tanto sovrascrivo l'array, oppure devo fare tipo:
ptr=malloc(.....);
ptr1=realloc(ptr,n);
free(ptr);
"tommy1996q":
mi chiedevo se il nuovo array si costruisse "sopra" quello vecchio, o fosse una copia in un' altra parte della memoria.
"man realloc":
The realloc() function changes the size of the memory block pointed to by ptr to size bytes. The contents will be unchanged in the range from the start of the region up to the minimum of the old and new sizes. If the new size is larger than the old size, the added memory will not be initialized. If ptr is NULL, then the call is equivalent to malloc(size), for all values of size; if size is equal to zero, and ptr is not NULL, then the call is equivalent to free(ptr). Unless ptr is NULL, it must have been returned by an earlier call to malloc(), calloc() or realloc(). If the area pointed to was moved, a free(ptr) is done.
Direi che dipende, ma generalmente viene spostato tutto il vettore.
"tommy1996q":
Cioè, posso fare:
ptr=malloc(.....); ptr=(ptr,n);
E precisamente cosa sarebbe?
Non è detto sia possibile utilizzare la memoria immediatamente successiva a quella che vuoi ridimensionare. Per esempio potrebbe essere già allocata per altro. Se non c'è spazio per poter allungare l'allocazione, realloc allocherà della nuova memoria e farà una copia del tuo blocco di memoria. In effetti realloc potrebbe farlo sempre, indipendentemente dallo spazio a sua disposizione dopo il blocco corrente. Nel caso in cui un nuovo blocco di memoria sia stato allocato, il blocco precedente viene deallocato da realloc. NON DEVI ASSOLUTAMENTE DEALLOCARE il tuo puntatore originario. Rischi solo di deallocare il tuo array nel caso in cui realloc non abbia allocato nuova memoria (ma solo ridimensionato quella precedente). Il modo corretto di usare realloc è il seguente:
Se non utilizzi i due puntatori come in questo caso rischi di perdere il riferimento al blocco originario che come ho scritto nel codice non viene modificato in caso di fallimento della funzione.
Non è comunque chiaro il senso del tuo codice.. Hai dimenticato qualcosa?
N.B. Tecnicamente, a seconda dello standard, ptr_new potrebbe essere NULL anche nel caso in cui n sia zero. Cioè nel caso in cui si sia deciso semplicemente di deallocare ptr_old. In questo caso ptr_old è stato deallocato e quindi non va toccato. Ma si tratta di una funzionalità abbastanza arcana che dipende dallo standard a cui si fa riferimento e alla particolare implementazione scelta dagli sviluppatori della libreria. Meglio quindi evitare di passare zero a realloc.
N.B. realloc può anche essere usata per rimpicciolire un blocco di memoria (liberando quindi parte della memoria precedentemente allocata). In questo caso è molto più probabile che non avvenga alcuno spostamento di memoria e che il puntatore rimanga quindi lo stesso.
ptr_new = realloc(ptr_old, n); if (!ptr_new) { /* realloc ha fallito.. */ /* gestisci questo caso.. qui ptr_old è ancora valido.. */ } ptr_old = ptr_new;
Se non utilizzi i due puntatori come in questo caso rischi di perdere il riferimento al blocco originario che come ho scritto nel codice non viene modificato in caso di fallimento della funzione.
Non è comunque chiaro il senso del tuo codice.. Hai dimenticato qualcosa?
N.B. Tecnicamente, a seconda dello standard, ptr_new potrebbe essere NULL anche nel caso in cui n sia zero. Cioè nel caso in cui si sia deciso semplicemente di deallocare ptr_old. In questo caso ptr_old è stato deallocato e quindi non va toccato. Ma si tratta di una funzionalità abbastanza arcana che dipende dallo standard a cui si fa riferimento e alla particolare implementazione scelta dagli sviluppatori della libreria. Meglio quindi evitare di passare zero a realloc.
N.B. realloc può anche essere usata per rimpicciolire un blocco di memoria (liberando quindi parte della memoria precedentemente allocata). In questo caso è molto più probabile che non avvenga alcuno spostamento di memoria e che il puntatore rimanga quindi lo stesso.
Grazie mille per i chiarimenti! Mi scuso per il codice che ho postato, è volutamente "scorretto", quello che mi premeva era far capire la domanda e non mi sono preoccupato di scrivere un codice formalmente corretto, per cui al posto di
int* ptr,ptr1;
ptr=malloc(sizeof(int));
ptr1=realloc(ptr,n);
ho scritto in modo molto più spreciso, mi scuso e cercherò di essere più attento nei prossimi post!
int* ptr,ptr1;
ptr=malloc(sizeof(int));
ptr1=realloc(ptr,n);
ho scritto in modo molto più spreciso, mi scuso e cercherò di essere più attento nei prossimi post!