Originariamente inviato da gio_gio88
Se inizializzo un array di puntatore a carattere in questo modo:
codice:
char *data[4]={"uno","due","tre","quattro"};
quando voglio stamparlo a video posso utilizzare questa procedura, giusto?
codice:
int i;
printf("L'archivio è composto da:");
for (i=0; i<4; ++i)
if (data[i] != NULL)
printf(" %s ", data[i]);
printf("\n");
Sì, ma la dichiarazione corretta è
codice:
const char *data[4]={"uno","due","tre","quattro"};
,
dal momento che le varie stringhe con cui inizializzi data sono dei const char *, ossia dei puntatori a delle stringhe che stanno nella tabella stringhe dell'eseguibile, che non è modificabile.
invece se l'archivio viene inizializzato attraverso una scanf come questa
codice:
char *data[4];
int i;
for (i=0; i<4; ++i)
scanf("%s", &data[i]);
devo, per stamparlo a video, utilizzare &.. come mai?
codice:
printf("L'archivio è composto da:");
for (i=0; i<7; ++i)
if (data[i] != NULL)
printf(" %s ", &datao[i]);
printf("\n");
Perché hai sbagliato. In primo luogo data non è un archivio, ma un array di puntatori a char. Se tu volessi usarlo con una scanf dovresti scrivere
codice:
scanf("%s", data[i]);
, passando in tal modo alla scanf un char *, ossia quello che si aspetta di ricevere. Passando alla scanf &data[i] invece tu stavi passando l'indirizzo di data+i, ossia un char **. La scanf, accettando dei parametri generici, non ti dà problemi, ma quel codice è sbagliato, visto che di fatto usi data per uno scopo diverso da quello per cui l'hai dichiarato e ad ogni iterazione sovrascrivi in parte i dati già scritti. Ad esempio usando questo codice:
codice:
#include <stdio.h>
int main(void)
{
char *data[4];
int i;
for (i=0; i<4; ++i)
{
printf("Inserisci la stringa %d: ",i);
scanf("%s", &data[i]);
}
for (i=0; i<4; ++i)
printf("Stringa %d: %s\n", i, &data[i]);
return 0;
}
già al momento della compilazione un compilatore furbo mi segnala che ci sono degli errori:
codice:
matteo@teoubuntu:~/cpp/test$ gcc archivio_errato.c -o archivio_errato.o
archivio_errato.c: In function ‘main’:
archivio_errato.c:11: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘char **’
archivio_errato.c:14: warning: format ‘%s’ expects type ‘char *’, but argument 3 has type ‘char **’
se poi provo ad eseguirlo
codice:
matteo@teoubuntu:~/cpp/test$ ./archivio_errato.o
Inserisci la stringa 0: 1234567890
Inserisci la stringa 1: abcdefghij
Inserisci la stringa 2: ABCDEFGHIJ
Inserisci la stringa 3: |!"£$%&/()
Stringa 0: 12345678abcdefghABCDEFGH|!"£$%&/()
Stringa 1: abcdefghABCDEFGH|!"£$%&/()
Stringa 2: ABCDEFGH|!"£$%&/()
Stringa 3: |!"£$%&/()
Su una macchina a 64 bit come la mia la sovrascrittura può essere meno evidente (inizia all'ottavo byte visto che con puntatori a 64 bit 1 char * = 8 char); in una macchina a 32 bit essa sarebbe iniziata al quarto byte (1 char * = 4 char).
Se ogni elemento di data puntasse a della memoria allocata potresti fare:
codice:
for (i=0; i<4; ++i)
{
printf("Inserisci la stringa %d: ",i);
scanf("%s", data[i]);
}
(programma di esempio:
codice:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char *data[4];
int i;
for (i=0; i<4; ++i)
{
data[i]=malloc(1024);
printf("Inserisci la stringa %d: ",i);
scanf("%s", data[i]);
}
for (i=0; i<4; ++i)
{
printf("Stringa %d: %s\n", i, data[i]);
free(data[i]);
}
return 0;
}
, che infatti non dà warning e funziona correttamente:
codice:
matteo@teoubuntu:~/cpp/test$ gcc archivio_corretto.c -o archivio_corretto.o
matteo@teoubuntu:~/cpp/test$ ./archivio_corretto.o
Inserisci la stringa 0: 1234567890
Inserisci la stringa 1: abcdefghij
Inserisci la stringa 2: ABCDEFGHIJ
Inserisci la stringa 3: |!"£$%&/()
Stringa 0: 1234567890
Stringa 1: abcdefghij
Stringa 2: ABCDEFGHIJ
Stringa 3: |!"£$%&/()
), ma mai e poi mai potresti fare questo senza allocare la memoria a cui puntino i vari elementi di data oppure facendoli puntare ad aree di memoria non scrivibile; non potresti fare ad esempio
codice:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char *data[4]={"uno", "due", "tre", "quattro"};
int i;
for (i=0; i<4; ++i)
{
printf("Inserisci la stringa %d: ",i);
scanf("%s", data[i]);
}
for (i=0; i<4; ++i)
printf("Stringa %d: %s\n", i, data[i]);
return 0;
}
senza ottenere comportamenti imprevisti, tra cui la sovrascrittura di una stringa con l'altra, il crash del programma o il suo funzionamento "strano".
Seconda domanda:
avendo queste istruzioni:
codice:
int iArr[15]={2,5,6,8};
int *iPtr;
printf("indirizzo di iArr: %X\n",iArr);
iPtr = iArr;
printf("indirizzo di iArr: %X\n",iPtr);
printf("primo elemento di iArr: %d\n",*iArr);
printf("secondo elemento di iArr: %d\n",*(iArr+1));
++iPtr;
printf("secondo elemento di iArr: %d\n",*iPtr);
come mai *iPtr punta al secondo elemento di iArr e non al primo visto che ha l'indirizzo base di quest'ultimo?
Perché hai incrementato di uno iPtr:
Come bisognerebbe fare per puntare al primo elemento? *(iPtr-1)?
Potresti non incrementare iPtr oppure usare la forma che dici tu.