DOMANDA [C] Matrice di Puntatori

JDany

Utente Attivo
461
24
CPU
Ryzen 9 3900x
Scheda Madre
ASUS H170-Pro
RAM
Corsair Vengeance LPX 2x8 GB
GPU
ZOTAC RTX 3070 TWIN EDGE OC
Monitor
Philips Gaming Monitor 24"
PSU
Corsair CX450M
Case
Sharkoon VS4-V
OS
Windows 11 Pro
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 Èlite
5,872
2,456
CPU
Ryzen 5700G
Dissipatore
Deep Cool castle 360 rgb v2
Scheda Madre
Rog Strix B550-F GAMING (WI-FI)
HDD
980 1TB
RAM
Ballistix 3600mhz 8Gbx2
GPU
1080 Ti Aorus xtreme
PSU
Corsair RM750x
nel senso che ti stampa 10 volte l'ultimo valore inserito nella matrice??
 

JDany

Utente Attivo
461
24
CPU
Ryzen 9 3900x
Scheda Madre
ASUS H170-Pro
RAM
Corsair Vengeance LPX 2x8 GB
GPU
ZOTAC RTX 3070 TWIN EDGE OC
Monitor
Philips Gaming Monitor 24"
PSU
Corsair CX450M
Case
Sharkoon VS4-V
OS
Windows 11 Pro
nel senso che ti stampa 10 volte l'ultimo valore inserito nella matrice??

Si proprio questo.

Ho provato a stampare anche ogni elemento ogni volta che mettevo la stringa però poi quando esco dal ciclo e stampo la matrice l'ultimo valore inserito viene stampato e gli altri non si sa dove finiscono.
 

Albo89

Utente Èlite
5,872
2,456
CPU
Ryzen 5700G
Dissipatore
Deep Cool castle 360 rgb v2
Scheda Madre
Rog Strix B550-F GAMING (WI-FI)
HDD
980 1TB
RAM
Ballistix 3600mhz 8Gbx2
GPU
1080 Ti Aorus xtreme
PSU
Corsair RM750x
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
 

JDany

Utente Attivo
461
24
CPU
Ryzen 9 3900x
Scheda Madre
ASUS H170-Pro
RAM
Corsair Vengeance LPX 2x8 GB
GPU
ZOTAC RTX 3070 TWIN EDGE OC
Monitor
Philips Gaming Monitor 24"
PSU
Corsair CX450M
Case
Sharkoon VS4-V
OS
Windows 11 Pro
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.
 

DispatchCode

Moderatore
Staff Forum
Utente Èlite
2,210
1,845
CPU
Intel I9-10900KF 3.75GHz 10x 125W
Dissipatore
Gigabyte Aorus Waterforce X360 ARGB
Scheda Madre
Asus 1200 TUF Z590-Plus Gaming ATX DDR4
HDD
1TB NVMe PCI 3.0 x4, 1TB 7200rpm 64MB SATA3
RAM
DDR4 32GB 3600MHz CL18 ARGB
GPU
Nvidia RTX 3080 10GB DDR6
Audio
Integrata 7.1 HD audio
Monitor
LG 34GN850
PSU
Gigabyte P850PM
Case
Phanteks Enthoo Evolv X ARGB
Periferiche
MSI Vigor GK30, mouse Logitech
Net
FTTH Aruba, 1Gb (effettivi: ~950Mb / ~480Mb)
OS
Windows 10 64bit / OpenSUSE Tumbleweed
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.
 

JDany

Utente Attivo
461
24
CPU
Ryzen 9 3900x
Scheda Madre
ASUS H170-Pro
RAM
Corsair Vengeance LPX 2x8 GB
GPU
ZOTAC RTX 3070 TWIN EDGE OC
Monitor
Philips Gaming Monitor 24"
PSU
Corsair CX450M
Case
Sharkoon VS4-V
OS
Windows 11 Pro

DispatchCode

Moderatore
Staff Forum
Utente Èlite
2,210
1,845
CPU
Intel I9-10900KF 3.75GHz 10x 125W
Dissipatore
Gigabyte Aorus Waterforce X360 ARGB
Scheda Madre
Asus 1200 TUF Z590-Plus Gaming ATX DDR4
HDD
1TB NVMe PCI 3.0 x4, 1TB 7200rpm 64MB SATA3
RAM
DDR4 32GB 3600MHz CL18 ARGB
GPU
Nvidia RTX 3080 10GB DDR6
Audio
Integrata 7.1 HD audio
Monitor
LG 34GN850
PSU
Gigabyte P850PM
Case
Phanteks Enthoo Evolv X ARGB
Periferiche
MSI Vigor GK30, mouse Logitech
Net
FTTH Aruba, 1Gb (effettivi: ~950Mb / ~480Mb)
OS
Windows 10 64bit / OpenSUSE Tumbleweed
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
Reazioni: Albo89

JDany

Utente Attivo
461
24
CPU
Ryzen 9 3900x
Scheda Madre
ASUS H170-Pro
RAM
Corsair Vengeance LPX 2x8 GB
GPU
ZOTAC RTX 3070 TWIN EDGE OC
Monitor
Philips Gaming Monitor 24"
PSU
Corsair CX450M
Case
Sharkoon VS4-V
OS
Windows 11 Pro
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.

Ancora non sono arrivato all'allocazione della memoria.

Comunque per l'overflow lo so stavo solo provando se l'algoritmo funzionava.
 

BrutPitt

Utente Attivo
1,166
1,262
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
Reazioni: Mursey e JDany

JDany

Utente Attivo
461
24
CPU
Ryzen 9 3900x
Scheda Madre
ASUS H170-Pro
RAM
Corsair Vengeance LPX 2x8 GB
GPU
ZOTAC RTX 3070 TWIN EDGE OC
Monitor
Philips Gaming Monitor 24"
PSU
Corsair CX450M
Case
Sharkoon VS4-V
OS
Windows 11 Pro
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.
 

BrutPitt

Utente Attivo
1,166
1,262
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
Reazioni: Mursey

JDany

Utente Attivo
461
24
CPU
Ryzen 9 3900x
Scheda Madre
ASUS H170-Pro
RAM
Corsair Vengeance LPX 2x8 GB
GPU
ZOTAC RTX 3070 TWIN EDGE OC
Monitor
Philips Gaming Monitor 24"
PSU
Corsair CX450M
Case
Sharkoon VS4-V
OS
Windows 11 Pro
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.
 

BrutPitt

Utente Attivo
1,166
1,262
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)
 

JDany

Utente Attivo
461
24
CPU
Ryzen 9 3900x
Scheda Madre
ASUS H170-Pro
RAM
Corsair Vengeance LPX 2x8 GB
GPU
ZOTAC RTX 3070 TWIN EDGE OC
Monitor
Philips Gaming Monitor 24"
PSU
Corsair CX450M
Case
Sharkoon VS4-V
OS
Windows 11 Pro
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:
 

Ci sono discussioni simili a riguardo, dai un'occhiata!

Entra

oppure Accedi utilizzando
Discord Ufficiale Entra ora!

Discussioni Simili