PDA

Visualizza la versione completa : [c++] creazione di matrice tramite funzioni void


pipporossonero
03-03-2012, 12:08
ciao a tutti, questa è la prima volta che vi scrivo vorrei pormi il mio problema nella speranza che qualcuno mi aiuti a risolverlo.


#include<iostream>
#include<new>
using namespace std;
void get(int***,int,FILE*);
void show(int**,int);
void alloca(int***,int);
void disalloca(int***,int,FILE*);
int main()
{
FILE*fp;
fp=fopen("matricedafile.txt","w+");
int **p;
int dim;
cout<<"qual'è la dimensione della matrice ?";
cin>>dim;
alloca(&p,dim);
get(&p,dim,fp);
show(p,dim);
disalloca(&p,dim,fp);
system("PAUSE");
return 0;
}
int i,j;
void alloca(int***q,int d)
{
cout<<"funzione alloca \n ";
*q=(int**)new int[d];
for(i=0;i<d;i++)
{
*q[i]=(int*)new int[d];
}
}
void get(int***q,int d,FILE*fu)
{
cout<<"funzione get \n";
cout<<"ora inserisci gli elementi della matrice!"<<endl;
for(i=0;i<d;i++)
{
for(j=0;j<d;j++)
{
cout<<"elemento "<<i+1<<""<<j+1<<" ";
cin>>*q[i][j];//
fprintf(fu,"%d",*q[i][j]);//
}
}
}
void show(int**q,int d)
{
cout<<"funzione show \n";
for(i=0;i<d;i++)
{
for(j=0;j<d;j++)
{
cout<<q[i][j]<<" ";
}
cout<<endl;
}
}
void disalloca(int***q,int d,FILE*fu)
{
cout<<"funzione disalloca\n";
for(i=0;i<d;i++)
{
delete(*q[i]);
}
delete(*q);
fclose(fu);
}

questo è il codice che ho scritto per allocare spazio in memoria, acquisire da tastiera la matrice, stamparla e deallocare lo spazio tutto tramite funzioni void...sicuramente ci sono degli errori durante l'allocazione perchè poi non mi permette di acquisire correttamente tutti i numeri della matrice.
grazie in anticipo.

ardito86
03-03-2012, 12:23
Spiega meglio il problema: il programma ti da errore mentre acquisisci o non acquisisce in modo corretto?

Una cosa che ho da ridire sul tuo programma: non è il massimo mischiare librerie standard C++ e C. Potrebbe portare a errori difficili da trovare o comunque, rende il programma instabile. O scrivi in C, o scrivi in C++

pipporossonero
03-03-2012, 12:30
Originariamente inviato da ardito86
non è il massimo mischiare librerie standard C++ e C. Potrebbe portare a errori difficili da trovare o comunque, rende il programma instabile. O scrivi in C, o scrivi in C++
Per prima cosa ti ringrazio per la risposta :);non penso sia quello il problema visto che ho una variante scritta in puro C che dà lo stesso problema (cioè non esce dalla funzione get).
Una volta inserito un certo numero di valori si blocca il programma,io per questo avevo pensato che fosse un problema di allocazione di memoria...

ardito86
03-03-2012, 12:39
Sembra molto impasticciato, non capisco la necessità di usare i tripli puntatori.

Comunque:

*q=(int**)new int[d];

l'operatore new[] rilascia un array di puntatori...non ha senso fare il cast per rilasciare un array di doppi puntatori. Così facendo gli dici che ogni intero a cui punta un puntatore deve essere a sua volta un puntatore....che ti fa andare in una zona di memoria sconosciuta.

*q= new int*[d];

Stessa cosa per:

*q[i]=new int*[d];

Così dovrebbe andare meglio...ma ripeto: non hai motivo di dichiarare all'inizio un doppio puntatore **p e passare ancora il suo indirizzo alla funzione alloca...

Se modificassi alloca() e get() e nel passargli il puntatore facessi:

alloca(p,dim);

il programma sarebbe più comprensibile

pipporossonero
03-03-2012, 12:51
la necessità del triplo puntatore sta nel fatto che io devo allocare una certa quantità di memoria e se faccio funzioni del tipo void alloca(int **,int) significa che dovrò fare una chiamata per valore e non per indirizzo !
Questo è un problema in quanto da ciò che ha spiegato il mio professore (o almeno da ciò che ho capito io e potrei anche aver capito male), se facciamo una chiamata per valore allora la funzione non modificherà i parametri attuali bensì lavorerà solo sui parametri formali quindi una chiamata per valore di tale funzione sarebbe inutile .Per questo penso sia necessaria una chiamata per indirizzo e nella dichiarazione della funzione devo quindi inserire un triplo puntatore.( ho già fatto lo stesso programma con funzioni non void ma che restituiscono un valore e funziona senza intoppi il mio problema rimane questo con funzioni void).
se ho detto assurdità perdonatemi e correggetemi :)

ardito86
03-03-2012, 13:06
Originariamente inviato da pipporossonero
la necessità del triplo puntatore sta nel fatto che io devo allocare una certa quantità di memoria e se faccio funzioni del tipo void alloca(int **,int) significa che dovrò fare una chiamata per valore e non per indirizzo !
Questo è un problema in quanto da ciò che ha spiegato il mio professore (o almeno da ciò che ho capito io e potrei anche aver capito male), se facciamo una chiamata per valore allora la funzione non modificherà i parametri attuali bensì lavorerà solo sui parametri formali quindi una chiamata per valore di tale funzione sarebbe inutile .Per questo penso sia necessaria una chiamata per indirizzo e nella dichiarazione della funzione devo quindi inserire un triplo puntatore.( ho già fatto lo stesso programma con funzioni non void ma che restituiscono un valore e funziona senza intoppi il mio problema rimane questo con funzioni void).
se ho detto assurdità perdonatemi e correggetemi :)

Tranquillo, se il parametro passato alla funzione è un puntatore il passaggio avverrà solamente per riferimento.

Per esempio:


void incrementa(int n){
n++;
}

main() {
int c = 5;
incrementa(c);
}


Questa funzione non ha effetto, perché sto passando per valore.



void incrementa(int *n){
(*n)++;
}

main() {
int num = 5;
int *c = & num;
incrementa(c);
}


Questa invece si, perché sto passando il puntatore e quindi è un passaggio per riferimento.
Ma in questo caso stiamo parlando di una variabile.

Il tuo **p è già un puntatore di suo
Quando ci sono i puntatori di mezzo, non hai alcun problema (devi solo stare attento ché i puntatori sono potenti solo se usati bene).

ramy89
03-03-2012, 13:23
Ardito, questa funzione qua:


void alloca(int***q,int d)
{
cout<<"funzione alloca \n ";
*q=(int**)new int[d];
for(i=0;i<d;i++)
{
*q[i]=(int*)new int[d];
}
}

Non funziona se gli passi un doppio puntatore proprio perchè i puntatori vengono passati per valore.
*q=(int**)new int[d];
Ha l' effetto di scrivere sul valore puntato da q la nuova area di memoria allocata.
Se era così:


void alloca(int**q,int d)
{
cout<<"funzione alloca \n ";
q=(int**)new int[d];
for(i=0;i<d;i++)
{
q[i]=(int*)new int[d];
}
}

Ogni riferimento a q andava perso perchè l' istruzione:
q=(int**)new int[d];
Era un assegnamento valido solo per il q locale a questa funzione.
E il q locale alla funzione è una copia del parametro.
Il passaggio per riferimento è questo:


void alloca(int**& q,int d)
{
cout<<"funzione alloca \n ";
q=(int**)new int[d];
for(i=0;i<d;i++)
{
q[i]=(int*)new int[d];
}
}

Così viene passato il riferimento a quel puntatore e non ci sono problemi.
Inoltre ricordo a pipporossonero che le cose allocate con new[] vanno liberate con delete[] e non con delete.

pipporossonero
03-03-2012, 13:38
void alloca(int**& q,int d)
{
cout<<"funzione alloca \n ";
q=(int**)new int[d];
for(i=0;i<d;i++)
{
q[i]=(int*)new int[d];
}
}

Così viene passato il riferimento a quel puntatore e non ci sono problemi.
Inoltre ricordo a pipporossonero che le cose allocate con new[] vanno liberate con delete[] e non con delete.
hai perfettamente ragione sul delete mea culpa, concordo con l'utilizzo dei reference nella funzione alloca ma se stessimo scrivendo in C e non in C++, il mio codice utilizzando i tripli puntatori e passando per indirizzo non sarebbe l'unica via percorribile ( e se si dove ho sbagliato ? )...grazie per la risposta !

ardito86
03-03-2012, 13:56
Non funziona se gli passi un doppio puntatore proprio perchè i puntatori vengono passati per valore.
Figura di merda...è vero :D Viene creata una nuova variabile all'interno della funzione e poi viene persa...

ramy89
03-03-2012, 15:08
Originariamente inviato da pipporossonero
hai perfettamente ragione sul delete mea culpa, concordo con l'utilizzo dei reference nella funzione alloca ma se stessimo scrivendo in C e non in C++, il mio codice utilizzando i tripli puntatori e passando per indirizzo non sarebbe l'unica via percorribile ( e se si dove ho sbagliato ? )...grazie per la risposta !

In C oltre alla variabili globali (sconsigliate) l' unico modo era usare i tripli puntatori.
Attenzione alla precedenza degli operatori:



void alloca(int***q,int d)
{
cout<<"funzione alloca \n ";
*q=(int**)new int* [d];
for(i=0;i<d;i++)
{
(*q)[i]=(int*)new int[d]; // l' operatore [] ha la precedenza
}
}


q è un puntatore a puntatore allocato nello stack, locale alla funzione alloca (è stato allocato automaticamente nello stack per contenere il valore di quello che nel main è &p).
Quando i vale zero non c'è problema ad accedere a *q[i] perchè i vale zero.
La tua intenzione non era:
-Prima spostarti di i posizioni da q;
-Poi deferenziare il risultato della sotto-espressione ottenuta (cioè q[i]).
Ma invece volevi:
-Deferenziare q;
-Spostarti di i posizioni da *q.
Perchè *q contiene quello che nel main è p, ma *(q+1) probabilmente non c'è nello stack.
E questo lo devi correggere in tutto il codice, non solo nella alloca.
Altra cosa: per la get non servivano i tripli puntatori visto che stai solo cambiando i valori contenuti nella matrice.Poi le variabili i e j non le dichiarare globali, ma instanziale nel for:


for(int i=0;i<d;i++) {...}





Figura di merda...è vero Viene creata una nuova variabile all'interno della funzione e poi viene persa...


Ma no anzi, le migliori cose si imparano sbagliando clamorosamente , perchè non te le dimentichi mai :mem:

Loading