[C++] Problema con matrici e funzioni

DajeForte
Il mio problema non saprei neanche bene spiegarlo (vista la mia ignoranza in materia).
Vorrei scrivere alcune funzioni con le matrici ed ho un problema sul tipo di variabili edil ritorno.

Per adesso avevo scrittoun programmino che permette di costruire una matrice

float Matrix()
{
int m_1;
int n_1;

cout << "Insert # rows matrix A; m_1: ";
cin >> m_1;
cout << "Insert # columns matrix A; n_1: ";
cin >> n_1;

float A[m_1][n_1];

cout << "Insert A values (by row): ";
for (int i=1; i++ <= m_1; )
{
for (int j=1; j++ <= n_1; )
{
cin >> A[j];
}
}


return A;
}

Ora il problema è che in main va tranquillamente ma io la voglio definire come funzione. Credo dunque che il problema sia sul return.

Grazie

Risposte
apatriarca
Per creare una matrice utilizzando la sintassi
float A[m_1][n_1];

è necessario che sia m_1 che n_1 siano costanti. Se queste dimensioni non sono conosciute a priori, è necessario far ricorso ad uno dei seguenti metodi:
1. creare una matrice con le dimensioni massime possibili;
2. usare l'allocazione dinamica della memoria.
Entrambe le soluzioni hanno i loro vantaggi e svantaggi. Che cosa stai cercando di fare esattamente?

DajeForte
Grazie della risposta.
Ti dico subito che l'allocazione dinamica è una cos che ho sentito e credo sia importante ma non ne so nulla (questo non vuol dire che la escludo).

Per quanta riguarda la mia finalità ora non ne ho una precisa ma mi sto costruendo un database con un po' di funzioni (diciamo che alcuni di questi tra i quali quello che ti ho riportato non hanno stretta necessità ma servono a darmi pratica e come puoi vedere a crearmi problemi)

Ti allego dunque un altro codice che fa la moltiplicazione tra due matrici.
Se ti va di dargli un'occhiata ed un giudizio da un occhio + esperto di c++.

Grazie mille.

float Matrix_prod (float A, float B)
{
float AB[m_1][n_2];

for (int i=1; i++ <= m_1; )
{
for (int j=1; j++ <= n_2; )
{
int k = 1;
AB[j] = 0;
while (k++ <= n_1)
{
AB[j] = AB[j] + *&A[k] * *&B[k][j];
}
}
}
return AB;
}

Ecco su questo già riscontravo il problema di farmi dare le dimensioni delle due matrici A e B che costituiscono le matrici input

Rggb1
Ci sono alcuni problemi concettuali - sembra tu stia programmando in Mat$$lab ;) Per esempio: gli indici partono sempre da 0, e gli incrementi come da te impostati potrebbero avere problemi.

Forse è meglio se utilizzi degli oggetti (vedo benissimo una classe 'Matrix' per queste operazioni). Ignoro però le tue conoscenze, e non vorrei complicarti la vita: certo dipende anche da quanto tempo ci puoi dedicare o anche quanto sia importante.

DajeForte
Ciao Rggb, infatti diciamo che la mia preparazione di programmazione si è evoluta con programmi tipo matlab, e non con un programma (fichissimo) ma che parte da 0, è una tabula rasa.

Queste cose dele classi me le devo ancora vedere (non ho neanche capito cosa siano), mi faccio un giro nelle dispense linkate e vedo se trovo qualcosa.

Una cosa: tu hai detto che potrebbero dare problemi alcune cose che ho scritto. Ecco ma potresti dirmelo?

Grazie

Rggb1
Per quanto riguarda la prima: gli array partono da indice zero, quindi se A[...] è un vettore di 'n' elementi, i suoi elementi sono
A[0], A[1], ... A[n-1]
equivalentemente se è una matrice (array di due dimensioni)

I valori di ritorno: in C (C++) - semplifico - non puoi passare ad una funzione una "matrice" o metterla come valore di ritorno, ma devi usare un suo puntatore, ovvero un oggetto che dice dove/come accedere a questa matrice; questo è sufficiente a compiere le tutte le operazioni che ti servono su quell'oggetto, ed in pratica è come passare/ritornare l'intero oggetto, ma devi comprendere la differenza del meccanismo per evitare errori.

Gli incrementi che hai impostato: premetto che il costrutto
for (a; b; c) exp;

è equivalente a scrivere
a;
while (b)
{
  exp;
  c;
}

Ora tu metti nel ciclo l'incremento assieme all'espressione di controllo ("guardia"), niente di male in ciò, ma comporta il fatto che l'incremento viene eseguito prima delle operazioni. Infatti il ciclo che hai messo (lo correggo per far partire gli indici da zero):
for (int j=0; j++ <= n_2; )
{
  int k = 0;
  AB[i][j] = 0;
  //ecc...
}

è equivalente a
int j=0;
while (j++ <= n_2)
{
  int k = 0;
  AB[i][j] = 0;
  //ecc...
  // in questo caso non c'e' il terzo elemento del "for()"
}

e qui ti accorgi di cosa succede: viene impostato 'j' a zero e subito incrementato, sì che il primo elemento al quale si accede è il secondo della matrice (di quela riga, per essere più precisi).

Questa breve digressione solo per farti riflettere su dove andare a parare: vuoi continuare su questa strada, o puoi accontentarti di una soluzione "messa lì" anche se non l'hai capita? Il C (C++) è un linguaggio molto potente, ma concettualmente molto "vicino alla macchina".

Per inciso, lo stile per i cicli for() che consiglio, per accedere a elementi in sequenza in un array, è sempre
for (i=0; i < num; i++)
{
  //accedo all'elemento
  val=elem[i];
  // scrivo l'elemento
  elem[i]=func(par1, par2);
}


PS. Scusa il "blablabla" :-D

DajeForte
"Rggb":
PS. Scusa il "blablabla" :-D

Ma di che!

Allora ho capito del fatto che gli array partono da 0, anche perchè sono appena entrato in possesso di un bestione da 1000 pagine di Bjarne Stroustrup.
Ho iniziato a sfogliarmelo ed ho visto questa cosa.
Ho anche visto (in relazione a quello che dici i due "segni" & e * e penso che sia questo quello a cui ti riferisci.
Allora & restituisce il nome (l'indirizzo) del box della variabile
int p=1;
cout << &p;

mi dovrebbe ridare l'indirizzo (una cosa tipo 2x0de46blabla)
ecco ma se io volessi salvare in un'altra variabile questo indirizzo, che definizione deve avere questa variabile;
ovvero va bene int ind=&p; mi pare che mi dava errore.

l'altro invece ridà il valore contenuto nella variabile all'indirizzo.
Quindi *ind mi dovrebbe dare p;
a questo punto &*p mi ridà cosa c'è in p; possiamo dire dunque che sono operatori inversi? Credo di si.

Per quanto riguarda la questione dei for si può costruire un for con un while e viceversa; mi viene da dire che uno utilizza il loop che meglio si addice alle particolari esigenze del ciclo in pafrticolare.

Un'ultima cosa (scusa tu ora il mio blabla) quando hai detto del j++ io sapevo e credo sia corretto che se il ++ è dopo la variabile lu prima fa l'operazione (in questo caso controllail vero o falso) e dopo incrementa.Se inve faccio ++j primaincrementa e dopo fa l'operazione.
Diciamo che poi il programma che ho scritto funziona quindi penso che questa logica rimanga.

Ti ringrazio delle risposte.

apatriarca
Il libro di Stroustrup è senza dubbio la "bibbia" del C++, ma se hai così fretta di imparare potrebbe essere comodo iniziare con un libro più immediato per poi tornare sullo Stroustrup in seguito per approfondire le tue conoscenze. Se sai un po' di inglese ti consiglierei di cercare Accelerated C++ che segue un approccio un po' particolare, ma ti permette di iniziare a scrivere programmi più interessanti abbastanza in fretta.

Tornando ai tuoi problemi. Le variabili che contengono l'indirizzo ad un'altra variabile si chiamano puntatori e sono definiti inserendo * dopo il tipo della variabile al quale appartiene l'indirizzo. Se vuoi quindi una variabile che contenga l'indirizzo della tua variabile p dovrai definire ind nel modo seguente:
int p = 1;
int * ind = &p;

L'operatore * e & sono effettivamente inversi ma non puoi scrivere &*p perché l'operatore * è applicabile solo ai puntatori e quindi puoi al massimo avere *&p che prima ottiene l'indirizzo di p (che ha tipo int*) e poi ottiene la variabile a cui punta cioè p. Puoi invece avere &*ind. C'è tantissimo altro da dire, troppo per un singolo post. Ma puoi trovare tutto questo (e molto altro) su qualsiasi manuale di C++.

I cicli sono intercambiabili. Puoi cioè sempre riscrivere del codice per usare un ciclo diverso. Va a preferenza personale.

j++ prima esegue l'istruzione in cui j è inclusa e poi incrementa la variabile, mentre ++j prima incrementa e poi usa la variabile. Personalmente preferisco usare sempre la seconda versione perché è normalmente più facile comprenderne la logica (a parte essere potenzialmente più efficiente). Nel tuo caso l'incremento viene eseguito subito dopo aver valutato la condizione e cioè subito prima di eseguire il contenuto del ciclo.

DajeForte
Perfetto grazie mille.

Pensoche mimetterò con un po' di calma a vedere questa bibbia con santa pazienza,
ti ringrazio avrei solo una domanda se faccio:

for( i, i++ <2, )
{
qualcosa che è funzione di i
}


l'incremento lo fa subitodopo aver verificato il vero falso della condizione o lo fa a fine iterazione (in poche parole in "qualcosa che è funzione di i" sarà gia incrementato o no).

Te mi hai detto a fine iterazione e credo sia così ma mi hai messo il dubbio.

Grazie mille ciao.

Rggb1
"DajeForte":
...Te mi hai detto a fine iterazione e credo sia così ma mi hai messo il dubbio.

Mi sembra abbia detto ciò che ho detto io: lo fa dopo aver valutato l'espressione, ma ovviamente prima delle altre istruzioni del ciclo:
"apatriarca":
...e cioè subito prima di eseguire il contenuto del ciclo

Vedo sopra che dicevi che da prove fatte (?) a te funziona in modo diverso, cioè l'incremento viene eseguito dopo le istruzioni contenute nel ciclo, il che non mi torna.

apatriarca
Nel tuo caso l'incremento viene eseguito subito dopo aver valutato la condizione e cioè subito prima di eseguire il contenuto del ciclo.

Come ti ho detto prima viene incrementato prima di "qualcosa che è funzione di i". Ed è proprio per la maggior difficoltà a comprenderne il significato che preferisco usare ++i. Nel tuo caso viene prima confrontato i con 2 e poi i viene incrementato. Ma è comunque un brutto modo di scrivere un ciclo for.

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.