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:
codice:
++iPtr;
Come bisognerebbe fare per puntare al primo elemento? *(iPtr-1)?
Potresti non incrementare iPtr oppure usare la forma che dici tu.