Visualizzazione dei risultati da 1 a 4 su 4
  1. #1

    [C] Delucidazione sui puntatori (MIE FAQ DA RISOLVERE)

    Salve, sto da poco studiando il linguaggio C, avrei delle domande da porvi in modo da comprende il tema in maniera ottimale.

    Prima domanda:

    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");
    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");
    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?
    Come bisognerebbe fare per puntare al primo elemento? *(iPtr-1)?


    Grazie!!

  2. #2
    Utente di HTML.it
    Registrato dal
    Jul 2008
    Messaggi
    1,326

    Re: [C] Delucidazione sui puntatori (MIE FAQ DA RISOLVERE)

    Originariamente inviato da gio_gio88
    Prima domanda:

    ... 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");
    Mi sembra molto strano che questo codice non ti dia problemi. Quando tu scrivi

    codice:
    char *data[4];
    stai dichiarando un array di 4 puntatori a char, tuttavia non allochi alcuno spazio in memoria per questi puntatori quindi, se nell'immissione dei dati da tastiera vai a sovrascrivere aree di memoria (non precedentemente allocate per le stringhe!) sensibili, è probabile che il programma crashi. Per risolvere o allochi spazio dinamicamente per ciascuna stringa (calloc(), malloc() ecc...) oppure lo fai staticamente, quindi una cosa tipo:

    codice:
    char data[4][20];
    dichiarazione con cui stai dicendo che il tuo array è costituito da 4 stringhe e per ciascuna c'è uno spazio in memoria per 20 caratteri. A questo punto, la lettura può avvenire così:

    codice:
    for ( i = 0; i < 4; i++ ) {
       printf("Scrivere la stringa di indice %d: ", i);
       scanf("%s", data[i]); /* senza la & */
    e la stampa con lo stesso codice che hai scritto inizialmente, senza la & nella printf().

    Originariamente inviato da gio_gio88
    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?
    Come bisognerebbe fare per puntare al primo elemento? *(iPtr-1)?
    Non ho capito quale sia il problema... se tu incrementi iPtr con questa istruzione

    ++iPtr;

    è normale che questo punti al secondo elemento dell'array...
    every day above ground is a good one

  3. #3

    Re: [C] Delucidazione sui puntatori (MIE FAQ DA RISOLVERE)

    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.
    Amaro C++, il gusto pieno dell'undefined behavior.

  4. #4
    Grazie mille ad entrambi, dopo aver postato la domanda continuando a studiarmi le istruzioni sono riuscito in parte a raggiungere lo scopo, con le vostre risposte ho tolto ogni dubbio..

    Grazie..

    Colgo l'occasione pr un altra domanda:

    ho creato una funzione di questo tipo

    codice:
    void RisultatiPartite (int n, int Risultati[][2], char Partite[][MAX])
    {
    	int i;
    	printf("Inserisci tutti i rispettivi risultati:");
    	for (i=0; i<n; ++i)
    	{
    		printf("\n%s: ", Partite[i]);
    		scanf("%d", &Risultati[i][1]);
    		printf(" - ");
    		scanf("%d", &Risultati[i][2]);
    	}
    }
    come potrei riuscire a prendere il valore in input senza andare a capo?

    codice:
     
    		scanf("%d", &Risultati[i][1]);
    		printf(" - ");
    		scanf("%d", &Risultati[i][2]);
    Grazie ancora!

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.