-

[DOMANDA] [C] Matrice di Puntatori

#1
Salve.

Non riesco a trovare il motivo per cui quando vado a stampare la matrice mi stampa sempre l'ultimo elemento.

C:
#include <stdio.h>
#include <stdlib.h>

void freeBuffer(void){
    while(getchar() != '\n');
}

int main(int argc, char *argv[]){
    
    char *matrice[10][1]; // Matrice di puntatori a char
    
    char array[32] = {0}; // Array usato per scrivere nella matrice
    
    
    /**
     * Scrivo nella matrice
     * attraverso un for
     */
    
    for(unsigned int i = 0;i<10;++i){
        
        scanf("%[^\n]s", array);
        matrice[i][0] = array; // Posizione colonna sempre 0
        printf("%2d: %s\n", i, matrice[i][0]);
        freeBuffer();
    }
    
    printf("\n\n");
    
    /**
     * Stampo la matrice
     * di puntatori
     */
    
    for(unsigned int i = 0;i<10;++i){
        printf("%s\n", matrice[i][0]); // vedi riga 23
    }
    
    getchar();
    getchar();
    return 0;
}
 

Albo89

Utente Attivo
2,599
798
Hardware Utente
CPU
i7 8750h
Hard Disk
256GB ssd + 1TB HDD
RAM
8GB DDR4
Scheda Video
GTX 1060 6GB
#4
il problema sta qui:
Codice:
matrice[i][0] = array
così tu assegni il puntatore dell'oggetto array alla matrice; quindi tutti e 10 i valori contengono puntatori che puntano allo stesso oggetto;
quindi ogni valore della matrice punterà all'oggetto array, che contiene l'ultimo dato che gli hai fatto leggere perchè ad ogni giro ne sovrascrivi il contenuto


prova a non usare la variabile array e a fare direttamente
Codice:
scanf("%[^\n]s", matrice[i][0]);
oppure usi la funzione strcpy


p.s. ho dato un'occhiata veloce, non ho visto se ci sono altri errori
p.p.s scusa ma sono pessimo a spiegare :D
 
#5
il problema sta qui:
Codice:
matrice[i][0] = array
così tu assegni il puntatore dell'oggetto array alla matrice; quindi tutti e 10 i valori contengono puntatori che puntano allo stesso oggetto;
quindi ogni valore della matrice punterà all'oggetto array, che contiene l'ultimo dato che gli hai fatto leggere perchè ad ogni giro ne sovrascrivi il contenuto


prova a non usare la variabile array e a fare direttamente
Codice:
scanf("%[^\n]s", matrice[i][0]);

p.s. ho dato un'occhiata veloce, non ho visto se ci sono altri errori
p.p.s scusa ma sono pessimo a spiegare :D
No tranquillo anzi grazie.

Comunque non sono d'accordo con nello scrivere direttamente nella matrice. Dato che è un puntatore non si può direttamente scrivere dentro.
 
455
284
Hardware Utente
CPU
Intel i7 6700HQ, 2.60Ghz, 4 core 8 threads
Scheda Madre
Asustek
Hard Disk
Hitachi 7200 rpm, 1TB
RAM
16GB DDR4 (2 slot su 4)
Scheda Video
Nvidia Geforce GTX 960M, 4GB
Scheda Audio
Realtek
Sistema Operativo
Windows 10 64bit
#6
No tranquillo anzi grazie.

Comunque non sono d'accordo con nello scrivere direttamente nella matrice. Dato che è un puntatore non si può direttamente scrivere dentro.
Che intendi?
E' un parametro valido per scanf.
 
455
284
Hardware Utente
CPU
Intel i7 6700HQ, 2.60Ghz, 4 core 8 threads
Scheda Madre
Asustek
Hard Disk
Hitachi 7200 rpm, 1TB
RAM
16GB DDR4 (2 slot su 4)
Scheda Video
Nvidia Geforce GTX 960M, 4GB
Scheda Audio
Realtek
Sistema Operativo
Windows 10 64bit
#8
Perchè non hai allocato la memoria.
Ciò che fai oltretutto non è nemmeno sicuro in quanto se vengono inseriti più di 32 caratteri in array si verificherebbe un overflow.
 
Mi Piace: Albo89
#10
Ciao.

Visto che sembra un esercizio scolastico, evito volutamente di darti direttamente la soluzione, ma cerco di farti capire un paio di inesattezze.

anzitutto, perche'?:
char *matrice[10][1];

Non e' propriamente un errore (infatti il compilatore lo accetta), ma considera che una dichiarazione di [1], che implica un solo elemento, e' (teoricamente) inutile:
char c[1];
o
char c;
possono memorizzare la stessa informazione, ma la prima implica un'indicizzazione (teoricamente) non necessaria.

Quindi la tua dichiarazione equivale a:
char *matrice[10];

che non e' una matrice di puntatori, ma un array di puntatori.

Ma questo non e' l'errore.
Come ha scritto Albo89, il problema del codice che hai riportato e' che memorizzi per 10 volte l'indirizzo di un UNICO array:
Bada bene, l'indirizzo, il puntatore, e' sempre lo stesso, in tutti e 10 i valori della matrice: mentre con la funzione scanf, vai a cambiare solo i valori all'interno dell'array, ma non il suo indirizzo (che e' fisso, per allocazione/dichiarazione).
Cosi' alla fine nella matrice ti ritrovi 10 valori uguali, dell'unico indirizzo di array... e quando stampi, ovviamente stampi il contenuto per 10 volte di array, che contiene (ovviamente!) solo i valori dell'ultima scanf.

Se il compito e' popolare una matrice di puntatori:
- Anzitutto dovresti dichiarare correttamente la matrice (e ci sei quasi ;-) )
- Poi dovresti avere piu' "indirizzi" da copiare all'intero della matrice (mentre nel codice ne hai uno solo che copi per 10 volte)
 
Ultima modifica:
Mi Piace: Mursey e JDany
#11
Ciao.

Visto che sembra un esercizio scolastico, evito volutamente di darti direttamente la soluzione, ma cerco di farti capire un paio di inesattezze.

anzitutto, perche'?:
char *matrice[10][1];

Non e' propriamente un errore (infatti il compilatore lo accetta), ma considera che una dichiarazione di [1], che implica un solo elemento, e' (teoricamente) inutile:
char c[1];
o
char c;
possono memorizzare la stessa informazione, ma la prima implica un'indicizzazione (teoricamente) non necessaria.

Quindi la tua dichiarazione equivale a:
char *matrice[10];

che non e' una matrice di puntatori, ma un array di puntatori.

Ma questo non e' l'errore.
Come ha scritto Albo89, il problema del codice che hai riportato e' che memorizzi per 10 volte l'indirizzo di un UNICO array:
Bada bene, l'indirizzo, il puntatore, e' sempre lo stesso, in tutti e 10 i valori della matrice: mentre con la funzione scanf, vai a cambiare solo i valori all'interno dell'array, ma non il suo indirizzo (che e' fisso, per allocazione).
Cosi' alla fine nella matrice ti ritrovi 10 valori uguali, dell'unico indirizzo di array... e quando stampi, ovviamente stampi il contenuto per 10 volte di array, che contiene (ovviamente!) solo i valori dell'ultima scanf.

Se il compito e' popolare una matrice di puntatori:
- Anzitutto dovresti allocare correttamente la matrice (e ci sei quasi ;-) )
- Poi dovresti avere piu' "indirizzi" da copiare all'intero della matrice (mentre nel codice ne hai uno solo che copi per 10 volte)
In partenza ti dico che non è un esercizio scolastico, sono solo io che mi esercito nella programmazione. :hihi:

La risposta alla prima domanda: ho messo
C:
char *matrice[10][1];
perché da quello che ho studiato, i puntatori a char possono contenere stringhe abbastanza lunghe, essendo che l'array stesso di char è un puntatore. L'idea era quella di formare una tabella di appunto 10 righe e scrivere sempre nella colonna 0, tanto essendo un puntatore può contenere roba.
Non avendo mai usato una matrice di puntatori scusa se faccio tante domande/imprecisioni.

Per quanto riguarda l'allocazione della memoria purtroppo ancora non ci sono arrivato, ancora sto studiando (sono autodidatta) i file.

Grazie comunque per la spiegazione.
 
#12
Un puntatore non contiene nient'altro che un indirizzo di memoria... o meglio "punta" a un indirizzo di memoria.
Di per se un puntatore e' un contenitore di "semplici" "numeri interi" (da 32 o 64 bit a seconda se il sistema operativo sia a 32 o 64 bit, appunto), quindi il puntatore non contiene null'altro che un indirizzo.

Ti faccio un esempio che forse e' piu' semplice (spero :-) ).

Quando dichiari:
C:
const char array[32] = "ciao mamma";
il compilatore assegna un'area di memoria contigua di 32 BYTE (visto che sono char), e quest'area di memoria deve pure essere identificata all'interno dell'intera memoria di sistema.
Cosi' come tu mnemonicamente la identifichi con array, il compilatore gli assegna un indirizzo numerico.
Facciamo conto che sia da 0x1234 (ipotizzando sia 32 bit) a 0x1254 (lunghezza 32 BYTE)... il puntatore e' un meccanismo che ti permette di accedere alle singole celle di un'area di memoria allocata in altro modo.

Cosi' avrai:
array[0] == 'c' e array[1] == 'i'
mentre
array == 0x1234
che e' equivalente a:
&array[0] == 0x1234
ma anche la seconda cella ha un indirizzo che la identifica, e cosi' via:
&array[1] == 0x1235 (incrementa di 1 perche' sono char)

C:
const char array2[] = "ciao sorella"; // supponiamo array2 venga allocato partendo da 0x5678
char *ptr[2] = { array, array2 };
avra'
ptr[0] == 0x1234 (visto che avevamo ipotizzato array allocato a quell'indirizzo)
prt[1] == 0x5678
mentre la 'c' e la 'i' dell'esempio precedente sono da cercarsi in
ptr[0][0] == 'c' e ptr[0][1] == 'i'
o
*ptr[0] == 'c' e *(ptr[0]+1) == 'i'

Nell'esempio il puntatore ti permette di accedere a 2 array distinti e di dimensioni diverse, soltanto utilizzando gli indici di una variabile (ptr), e senza dover copiare TUTTI i dati, ma solo gli indirizzi... ma i dati devono essere gia' allocati o dichiarati (array e array2).

Tutto questo per dirti che un puntatore di per se' non contiene nulla, se non un numero: l'indirizzo
Il puntatore nell'esempio sopra contiene SOLO i numeri 0x1234 e 0x5678... mentre i "dati" appartengono alle allocazioni/dichiarazioni di array e array2: sono gli array, le matrici che una volta allocate/dichiarate possono contenere "stringhe abbastanza lunghe", come hai scritto tu.

Alla fine, quella matrice di punatori, conterra' solo ed esclusivamente una serie di numeri, che come detto sono gli indirizzi delle "stringhe" allocate altrove (ovvero l'indirizzo al primo elemento dell'array di char).
 
Ultima modifica:
Mi Piace: Mursey
#13
Un puntatore non contiene nient'altro che un indirizzo di memoria... o meglio "punta" a un indirizzo di memoria.
Di per se un puntatore e' un contenitore di "semplici" "numeri interi" (da 32 o 64 bit a seconda se il sistema operativo sia a 32 o 64 bit, appunto), quindi il puntatore non contiene null'altro che un indirizzo.

Ti faccio un esempio che forse e' piu' semplice (spero :-) ).

Quando dichiari:
C:
const char array[32] = "ciao mamma";
il compilatore assegna un'area di memoria contigua di 32 BYTE (visto che sono char), e quest'area di memoria deve pure essere identificata all'interno dell'intera memoria di sistema.
Cosi' come tu mnemonicamente la identifichi con array, il compilatore gli assegna un indirizzo numerico.
Facciamo conto che sia da 0x1234 (ipotizzando sia 32 bit) a 0x1254 (lunghezza 32 BYTE)... il puntatore e' un meccanismo che ti permette di accedere alle singole celle di un'area di memoria allocata in altro modo.

Cosi' avrai:
array[0] == 'c' e array[1] == 'i'
mentre
array == 0x1234
che e' equivalente a:
&array[0] == 0x1234
ma anche la seconda cella ha un indirizzo che la identifica, e cosi' via:
&array[1] == 0x1235 (incrementa di 1 perche' sono char)

C:
const char array2[] = "ciao sorella"; // supponiamo array2 venga allocato partendo da 0x5678
char *ptr[2] = { array, array2 };
avra'
ptr[0] == 0x1234 (visto che avevamo ipotizzato array allocato a quell'indirizzo)
prt[1] == 0x5678
mentre la 'c' e la 'i' dell'esempio precedente sono da cercarsi in
ptr[0][0] == 'c' e ptr[0][1] == 'i'
o
*ptr[0] == 'c' e *(ptr[0]+1) == 'i'

Nell'esempio il puntatore ti permette di accedere a 2 array distinti e di dimensioni diverse, soltanto utilizzando gli indici di una variabile (ptr), e senza dover copiare TUTTI i dati, ma solo gli indirizzi... ma i dati devono essere gia' allocati o dichiarati (array e array2).

Tutto questo per dirti che un puntatore di per se' non contiene nulla, se non un numero: l'indirizzo... sono gli array, le matrici che una volta allocate/dichiarate possono contenere "stringhe abbastanza lunghe", come hai scritto tu.

Alla fine, quella matrice di punatori, conterra' solo ed esclusivamente una serie di numeri, che come detto sono gli indirizzi delle "stringhe" allocate altrove (ovvero l'indirizzo al primo elemento dell'array di char).
Se non lo sapessi tutta sta roba sarei rimasto a bocca aperta. Spieghi veramente bene.

Comunque si ho capito però come hai detto tu dovrei creare tipo, per esempio, 10 variabili array; a quel punto però non avrebbe senso, se io voglio per esempio scrivere 23 righe non posso, mi fermerei alla 10. Quindi a questo punto sarebbe meglio usare una semplice matrice di char, invece di una matrice di puntatori.
 
#14
Comunque si ho capito però come hai detto tu dovrei creare tipo, per esempio, 10 variabili array; a quel punto però non avrebbe senso, se io voglio per esempio scrivere 23 righe non posso, mi fermerei alla 10. Quindi a questo punto sarebbe meglio usare una semplice matrice di char, invece di una matrice di puntatori.
Per questo pensavo fosse un esercizio. ;-)
Una matrice di puntatori avrebbe senso con l'allocazione dinamica, che puoi fare all'interno di un ciclo iterativo (for)... e ogni scanf acquisisce il dato nell'array appena allocato dinamicamente... il cui indirizzo poi finisce nella Matrice (e che serve anche per la deallocazione)
 
#15
Per questo pensavo fosse un esercizio. ;-)
Una matrice di puntatori avrebbe senso con l'allocazione dinamica, che puoi fare all'interno di un ciclo iterativo (for)... e ogni scanf acquisisce il dato nell'array appena allocato dinamicamente... il cui indirizzo poi finisce nella Matrice (e che serve anche per la deallocazione)
Si infatti adesso ho risolto con una semplice matrice.

Comunque grazie davvero, mi hai fatto capire che mi devo muovere a studiare il capito dell'allocazione della memoria. :brindiamo:
 

Discussioni Simili


Entra