Puntatori e costanti

Forum dedicato alla programmazione.

Moderatore: Staff

Regole del forum
1) Citare in modo preciso il linguaggio di programmazione usato.
2) Se possibile portare un esempio del risultato atteso.
3) Leggere attentamente le risposte ricevute.
4) Scrivere i messaggi con il colore di default, evitare altri colori.
5) Scrivere in Italiano o in Inglese, se possibile grammaticalmente corretto, evitate stili di scrittura poco chiari, quindi nessuna abbreviazione tipo telegramma o scrittura stile SMS o CHAT.
6) Appena registrati è consigliato presentarsi nel forum dedicato.

La non osservanza delle regole porta a provvedimenti di vari tipo da parte dello staff, in particolare la non osservanza della regola 5 porta alla cancellazione del post e alla segnalazione dell'utente. In caso di recidività l'utente rischia il ban temporaneo.
Rispondi
afterjames
Linux 0.x
Linux 0.x
Messaggi: 64
Iscritto il: lun 14 gen 2008, 14:14

Puntatori e costanti

Messaggio da afterjames »

Salve a tutti, ho un dubbio amletico sui puntatori in C.Ho sempre saputo che un buffer si può dichiarare indifferentemente come:

Codice: Seleziona tutto


char * const buffer1="blablabla";

oppure come un array :

Codice: Seleziona tutto


char buffer2[]="blablabla";

essendo un array equivalente ad un puntatore costante a dati variabili, cioè in cui non è possibile cambiare l'indirizzo a cui punta ma soltanto i valori "puntati".

Era tutto abbastanza chiaro, finchè un giorno non provai a fare :

Codice: Seleziona tutto

char *const s="bla bla";
char * ptr;
ptr = strtok(s," ");
Ottenendo un errore di segmentazione..Cosa che non accade se invece faccio:

Codice: Seleziona tutto

char  s[]="bla bla";
char * ptr;
ptr = strtok(s," ");
Che differenza c'è tra la versione con il puntatore e quella con il vettore?

Avatar utente
Calzo
Linux 1.x
Linux 1.x
Messaggi: 112
Iscritto il: sab 6 ott 2007, 22:21
Slackware: 10.2 | 13
Desktop: Fluxbox | KDE
Località: MN

Re: Puntatori e costanti

Messaggio da Calzo »

Dovrebbe essere legato al fatto che definendo una stringa tra *s="" (o const *s="") viene allocata una zona di memoria read-only.
Infatti se fai:

Codice: Seleziona tutto

char s[]="abc";
char t[]="123";
char *x="def";
char *y="456";

void main() {
   printf("%X\n%X\n%X\n%X\n",s,t,x,y);
}
vedrai che la memoria non è contigua. A me x esempio torna questo:

Codice: Seleziona tutto

80495F0
80495F4
80484D4
80484D8
Inoltre la funzione che hai usato tu modifica direttamente *s. Ti dovrebbe dare un seg fault anche se fai s[1]='x'.
Ultima modifica di Calzo il mer 23 gen 2008, 23:20, modificato 1 volta in totale.

Avatar utente
phobos3576
Staff
Staff
Messaggi: 2980
Iscritto il: dom 17 apr 2005, 0:00
Slackware: 13.1
Kernel: 2.6.37-smp
Desktop: KDE 4.5.3

Re: Puntatori e costanti

Messaggio da phobos3576 »

Se apri un terminale e dai il comando man strtok puoi notare che:

Codice: Seleziona tutto

Avoid using these functions.  If you do use them, note that:

              These functions modify their first argument.

              These functions cannot be used on constant strings.

              The identity of the delimiting character is lost.

              The  strtok() function uses a static buffer while parsing, so it's
              not thread safe. Use strtok_r() if this matters to you.
Quindi, strtok modifica il suo primo argomento!

La stringa "bla bla", creata come hai fatto tu, è una stringa costante; il compilatore la sistema nel blocco dati globale del programma.
Come risulta dallo standard ANSI C: "se si tenta di modificare una stringa costante, il risultato è indefinito".
E' la stessa situazione che si verifica quando si scrive:

Codice: Seleziona tutto

printf("%s\n", "ciao");
La stringa "ciao", non avendo un nome, non risulta accessibile in scrittura.

Il modo corretto di procedere consiste nello scrivere, ad esempio:

Codice: Seleziona tutto

char mystr[] = "bla bla";
char *s = mystr;

afterjames
Linux 0.x
Linux 0.x
Messaggi: 64
Iscritto il: lun 14 gen 2008, 14:14

Re: Puntatori e costanti

Messaggio da afterjames »

Allora..Due cose:La stringa così dichiarata:

Codice: Seleziona tutto

char *const str="blablabla";

Non è costante, in quanto è il puntatore ad essere costante(e non i valori puntati!).Questa è una stringa costante:

Codice: Seleziona tutto


const char* strcost="blablabla";

Ora, utilizzando la strtok, anche con una semplice:

Codice: Seleziona tutto


char *str="bla blabla";
char *ptr;

ptr=strtok(ptr," ");
Ottengo ugualmente un errore di segmentazione..Ma dovrei aver capito perchè!In realtà c'è differenza tra il dichiarare una stringa come un buffer e come un puntatore.Su un manuale ho letto che:

"Alcuni compilatori potrebbero sistemare una variabile di tipo char* che sia stata inizializzata con una stringa letterale,
in una locazione di memoria in cui non possa essere modificata :-k "

Dovrebbe essere per questo il motivo..Grazie a tutti

Avatar utente
targzeta
Iper Master
Iper Master
Messaggi: 6631
Iscritto il: gio 3 nov 2005, 14:05
Nome Cognome: Emanuele Tomasi
Slackware: 64-current
Kernel: latest stable
Desktop: IceWM
Località: Carpignano Sal. (LE) <-> Pisa

Re: Puntatori e costanti

Messaggio da targzeta »

afterjames ha scritto:Allora..Due cose:La stringa così dichiarata:

Codice: Seleziona tutto

char *const str="blablabla";

Non è costante, in quanto è il puntatore ad essere costante(e non i valori puntati!).
Errore, questa è una dichiarazione di puntatore costante a stringa che viene memorizzata in un area di memoria in read only, quindi, se vuoi è costante.

Con questa dichiarazione, anche fare

Codice: Seleziona tutto

str[0]='c';
non è valido.

Per usare una funzione che modifica l'area di memoria, devi o usare l'allocazione dinamica, oppure fare una dichiarazione del tipo:

Codice: Seleziona tutto

char str[]="blablabla";
in questo caso, str punterà ad una locazione di memoria che verrà allocata in fase di esecuzione e che conterrà la stringa "blablabla".
Nota che in questo caso, str è ancora un puntatore costante, nel senso che non è valido fare:

Codice: Seleziona tutto

str="pollo";
ma in questo caso è possibile modificare il contenuto di memoria a cui esso punta.

La tua dichiarazione invece è molto più restrittiva, il tuo puntatore str non può puntare a nient'altro che alla stringa "blablabla", e, l'area di memoria che contiene la stringa "blablabla" non può essere modificato. La tua dichiarazione è simile a questa:

Codice: Seleziona tutto

const char str[]="blablabla";
Spina
Se pensi di essere troppo piccolo per fare la differenza, prova a dormire con una zanzara -- Dalai Lama

Avatar utente
robbybby
Linux 4.x
Linux 4.x
Messaggi: 1223
Iscritto il: sab 16 dic 2006, 10:48
Slackware: 13.1 / 64 bit
Kernel: 3.3.x
Desktop: KDE 4.4.5
Località: Fra Trantor e Terminus

Re: Puntatori e costanti

Messaggio da robbybby »

Io evito la strtok come la peste! Mi ha dato un sacco di problemi appena un programma in cui la usava e' passato da single thread a multi thread.
Preferisco fare il parsing usando la strchr(). Alla fine e' comoda uguale, ed esente da problemi in programmi multithreding (semplicemente perche' non c'e' il buffer statico, e i puntatori ai vari token me li tengo io su variabili automatiche, quindi sul mio stack).

Rispondi