DOMANDA [C] Matrice di Puntatori

JDany

Utente Attivo
449
24
CPU
Intel Core i5 7500
Scheda Madre
ASUS H170-Pro
HDD
Seagate 1 TB
RAM
Corsair Vengeance LPX 2x8 GB
GPU
NVIDIA GTX 1050 Ti
Monitor
Philips Gaming Monitor 24"
PSU
Corsair CX450M
Case
Sharkoon VS4-V
OS
Windows 10 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
4,968
1,948
nel senso che ti stampa 10 volte l'ultimo valore inserito nella matrice??
 

JDany

Utente Attivo
449
24
CPU
Intel Core i5 7500
Scheda Madre
ASUS H170-Pro
HDD
Seagate 1 TB
RAM
Corsair Vengeance LPX 2x8 GB
GPU
NVIDIA GTX 1050 Ti
Monitor
Philips Gaming Monitor 24"
PSU
Corsair CX450M
Case
Sharkoon VS4-V
OS
Windows 10 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
4,968
1,948
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
449
24
CPU
Intel Core i5 7500
Scheda Madre
ASUS H170-Pro
HDD
Seagate 1 TB
RAM
Corsair Vengeance LPX 2x8 GB
GPU
NVIDIA GTX 1050 Ti
Monitor
Philips Gaming Monitor 24"
PSU
Corsair CX450M
Case
Sharkoon VS4-V
OS
Windows 10 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

Utente Attivo
1,168
771
CPU
Intel i7 6700HQ, 2.60Ghz, 4 core 8 threads
Scheda Madre
Asustek
HDD
Hitachi 7200 rpm, 1TB
RAM
16GB DDR4 (2 slot su 4)
GPU
Nvidia Geforce GTX 960M, 4GB
Audio
Realtek
Net
30Mbps/3Mbps con Eolo
OS
Windows 10 64bit
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
449
24
CPU
Intel Core i5 7500
Scheda Madre
ASUS H170-Pro
HDD
Seagate 1 TB
RAM
Corsair Vengeance LPX 2x8 GB
GPU
NVIDIA GTX 1050 Ti
Monitor
Philips Gaming Monitor 24"
PSU
Corsair CX450M
Case
Sharkoon VS4-V
OS
Windows 10 Pro

DispatchCode

Utente Attivo
1,168
771
CPU
Intel i7 6700HQ, 2.60Ghz, 4 core 8 threads
Scheda Madre
Asustek
HDD
Hitachi 7200 rpm, 1TB
RAM
16GB DDR4 (2 slot su 4)
GPU
Nvidia Geforce GTX 960M, 4GB
Audio
Realtek
Net
30Mbps/3Mbps con Eolo
OS
Windows 10 64bit
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.
 
  • Like
Reactions: Albo89

JDany

Utente Attivo
449
24
CPU
Intel Core i5 7500
Scheda Madre
ASUS H170-Pro
HDD
Seagate 1 TB
RAM
Corsair Vengeance LPX 2x8 GB
GPU
NVIDIA GTX 1050 Ti
Monitor
Philips Gaming Monitor 24"
PSU
Corsair CX450M
Case
Sharkoon VS4-V
OS
Windows 10 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
443
408
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:
  • Like
Reactions: Mursey e JDany

JDany

Utente Attivo
449
24
CPU
Intel Core i5 7500
Scheda Madre
ASUS H170-Pro
HDD
Seagate 1 TB
RAM
Corsair Vengeance LPX 2x8 GB
GPU
NVIDIA GTX 1050 Ti
Monitor
Philips Gaming Monitor 24"
PSU
Corsair CX450M
Case
Sharkoon VS4-V
OS
Windows 10 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
443
408
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:
  • Like
Reactions: Mursey

JDany

Utente Attivo
449
24
CPU
Intel Core i5 7500
Scheda Madre
ASUS H170-Pro
HDD
Seagate 1 TB
RAM
Corsair Vengeance LPX 2x8 GB
GPU
NVIDIA GTX 1050 Ti
Monitor
Philips Gaming Monitor 24"
PSU
Corsair CX450M
Case
Sharkoon VS4-V
OS
Windows 10 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
443
408
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
449
24
CPU
Intel Core i5 7500
Scheda Madre
ASUS H170-Pro
HDD
Seagate 1 TB
RAM
Corsair Vengeance LPX 2x8 GB
GPU
NVIDIA GTX 1050 Ti
Monitor
Philips Gaming Monitor 24"
PSU
Corsair CX450M
Case
Sharkoon VS4-V
OS
Windows 10 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:
 

Entra

oppure Accedi utilizzando

Hot: E3 2021, chi ti è piaciuto di più?

  • Ubisoft

    Voti: 36 22.9%
  • Gearbox

    Voti: 3 1.9%
  • Xbox & Bethesda

    Voti: 100 63.7%
  • Square Enix

    Voti: 13 8.3%
  • Capcom

    Voti: 7 4.5%
  • Nintendo

    Voti: 21 13.4%
  • Altro (Specificare)

    Voti: 15 9.6%

Discussioni Simili