[C++] Far scalare le componenti di un vettore
Salve a tutti.
Mi rendo conto che l'esercizio seguente sarà banale, ma non amando la materia mi sono esercitato decisamente poco quindi non escludo che l'errore si annida dove non sospetto.
Il testo mi chiede di costruire un array con $N$ componenti che decido io.
Poi mi dice di scrivere il codice che trasla queste componenti, cioè le fa avanzare di $k$ posti, ad es
$(1,2,3,4,5)$ traslato di $2$ posti diventa
$(4,5,1,2,3)$
La "difficoltà" sta nel fatto che non basta dirgli $a_1=a_(1+k)$ perchè potrebbe pure riavvolgersi, come succese a $4$ e $5$ nel caso precedente.
Costruito l'array, ho scritto una soluzione che però mi spara numeri a capocchia, anche enormi. Riporto il codice che ad esempio dovrebbe stamparmi solo la prima componente del nuovo vettore (quello traslato).
Matematicamente è giusto, ho verificato. Dove è che sbaglio? Osservazioni di ogni genere sono gradite.
Grazie in anticipo a tutti. A presto!
Mi rendo conto che l'esercizio seguente sarà banale, ma non amando la materia mi sono esercitato decisamente poco quindi non escludo che l'errore si annida dove non sospetto.
Il testo mi chiede di costruire un array con $N$ componenti che decido io.
Poi mi dice di scrivere il codice che trasla queste componenti, cioè le fa avanzare di $k$ posti, ad es
$(1,2,3,4,5)$ traslato di $2$ posti diventa
$(4,5,1,2,3)$
La "difficoltà" sta nel fatto che non basta dirgli $a_1=a_(1+k)$ perchè potrebbe pure riavvolgersi, come succese a $4$ e $5$ nel caso precedente.
Costruito l'array, ho scritto una soluzione che però mi spara numeri a capocchia, anche enormi. Riporto il codice che ad esempio dovrebbe stamparmi solo la prima componente del nuovo vettore (quello traslato).
Matematicamente è giusto, ho verificato. Dove è che sbaglio? Osservazioni di ogni genere sono gradite.
Grazie in anticipo a tutti. A presto!
int N, h; double x[50]; printf("Numero di componenti del vettore: N="); scanf("%i", &N); while (N>50) {printf("N non deve essere >50, digita altro numero\n\n"); printf("Numero di componenti del vettore: N="); scanf("%i", &N);} for (h=1; h<N+1; h++) { printf("La componente numero %i sia= ", h); scanf("%d",&x[h-1]); } printf("\nScrittura componenti dalla prima all'n-esima\n"); int j=1; while (j<N+1) {printf("\n%d\n", x[j-1]); j++ ;}; int k; printf("Scrivi di quanti posti devo traslare le coordinate: k="); scanf("%i", &k); int m=1; double y[50]; for(m; m<N+1; m++) {y[m-1]=x[(m-1-k)%(N)];}; printf("\n\n%i\n\n", y[0]); system("PAUSE"); return 0; }
Risposte
for(m; m<N+1; m++) {y[m-1]=x[(m-1-k)%(N)];};
mi spieghi cosa fa questa istruzione ? non mi è molto chiara.
Io farei così:
farei una piccola routine che ti trasla il vettore di una sola posizione (magari potresti passare alla stessa anche il senso [orario - antiorario]. Attenzione che hai bisogno di una variabile di appoggio, per non perdere il contenuto della cella che stai trasferendo.
Se questa routine funziona correttamente, la esegui tante volte (il tuo K ).
Qualcuno dirà, che cosi' facendo non è molto efficiente. Io preferisco far lavorare un po di piu' il computer, pur di avere un codice piu' lineare possibile.

Ciao Umby, grazie per la risposta.
Sostanzialmente quel ciclo for pensavo dovesse fare quello che ora ti mostro come esempio.
Se ad esempio avessi
$x_0$, $x_1$, $x_2$, $x_3$ e volessi traslare di 1, cioè $k=1$ ottengo
$x_3$, $x_0$, $x_1$, $x_2$ cioè, dette $y$ le nuove componenti
$y_0=x_3$
$y_1=x_0$ etc.
Cioè il codice prende la posizione del vettore, le leva $k$ e calcola modulo $N$, ad esempio $y_0$ (m=1, inizio ciclo) di prima proviene da $x_3$ poiché $1-1-1$ cioè $-1$ ovvero $3$ modulo4.
Mi sta venendo il sospetto che mettendo la variabile m in quella maniera ho scritto qualche bestemmia, ma aspetto conferme di ciò
Cosa intendi di preciso con "routine"?
Avoglia, soprattutto nelle condizioni in cui sono ora non posso permettermi troppi fronzoli.
L'importante è che giri, poi vediamo.
Ciao e grazie ancora!
Sostanzialmente quel ciclo for pensavo dovesse fare quello che ora ti mostro come esempio.
Se ad esempio avessi
$x_0$, $x_1$, $x_2$, $x_3$ e volessi traslare di 1, cioè $k=1$ ottengo
$x_3$, $x_0$, $x_1$, $x_2$ cioè, dette $y$ le nuove componenti
$y_0=x_3$
$y_1=x_0$ etc.
Cioè il codice prende la posizione del vettore, le leva $k$ e calcola modulo $N$, ad esempio $y_0$ (m=1, inizio ciclo) di prima proviene da $x_3$ poiché $1-1-1$ cioè $-1$ ovvero $3$ modulo4.
Mi sta venendo il sospetto che mettendo la variabile m in quella maniera ho scritto qualche bestemmia, ma aspetto conferme di ciò

Se questa routine funziona correttamente, la esegui tante volte (il tuo K ).
Cosa intendi di preciso con "routine"?
Qualcuno dirà, che cosi' facendo non è molto efficiente. Io preferisco far lavorare un po di piu' il computer, pur di avere un codice piu' lineare possibile.
Avoglia, soprattutto nelle condizioni in cui sono ora non posso permettermi troppi fronzoli.
L'importante è che giri, poi vediamo.

Ciao e grazie ancora!
Il problema è che % non è il modulo ma il resto e quindi per numeri negativi restituisce un valore diverso. Se vuoi usare % come modulo, devi fare in modo che il numero sia sempre positivo. Nel tuo caso invece di togliere $k$ aggiungi $N - k$ (ovviamente si suppone che $k$ sia minore di $N$).
Ieri avevo scritto di fretta perché ero stanco. Hai visto che con la tua tecnica si presentano alcuni problemi dovuti alla differenza tra l'operazione di resto di una divisione e quella di modulo. Anche con il mio consiglio si potrebbero verificare problemi quando $k > N$. Ma per risolvere il problema è sufficiente cambiare il punto di vista. Nel tuo caso calcoli per ogni posizione dell'array destinazione quale elemento dell'array originale ci devi scrivere. È però possibile ragionare al contrario: considerare ogni elemento dell'array originale e scriverlo nella posizione corretta in quello di destinazione.
In questo modo $k+i$ è sempre positivo e quindi l'operatore di resto si comporta come il modulo.
P.S. Perché fai partire i contatori da $1$? In C è buona norma farli sempre partire da $0$. In questo modo non devi scrivere $m-1$ in continuazione...
for (i = 0; i < N; ++i) { y[(k+i) % N] = x[i]; }
In questo modo $k+i$ è sempre positivo e quindi l'operatore di resto si comporta come il modulo.
P.S. Perché fai partire i contatori da $1$? In C è buona norma farli sempre partire da $0$. In questo modo non devi scrivere $m-1$ in continuazione...
"Steven":
Cosa intendi di preciso con "routine"?
Per routine (in cobol si chiama section), si intende un gruppo di istruzioni che fanno una certa operazione specifica. Devi intenderla come una scatola nera, che gli dai alcuni parametri in input e ti restituisce altri valori (output). La routine puoi richiamarla piu' volte in un programma, per scopi diversi, e ti da la possibilita' di non scrivere piu volte lo stesso codice.
Ti scrivo del codice in cobol (il linguaggio è indipendente da un algoritmo)
01 INIZIO SECTION. 02 accept "Numero di elementi del vettore" numele 03 accept "Numero di translazioni " numtra 04 accept "Orientamento (D/S) " orient 05 if orient not equal "D" and 06 not equal "S" 07 display message box "Errore dati" 08 go to ex-inizio. 09 perform varying ind from 1 by 1 until ind > numele 10 move ind to tabella (ind) 11 end-perform 12 if orient = "D" perform shift-dx numtra times end-if 13 if orient = "S" perform shift-sx numtra times end-if 14 display message box tabella. 15 EX-INIZIO. EXIT SECTION. 16 *** 17 SHIFT-DX SECTION. 18 move tabella(numele) to servizio 19 perform varying ind from numele by -1 until i = 1 20 move tabella (i - 1) to tabella (i) 21 end-perform 22 move servizio to tabella (1). 23 EX-SHIFT-DX. EXIT SECTION. 24 *** 25 SHIFT-SX SECTION. 26 move tabella(1) to servizio 27 perform varying ind from 1 by 1 until i = numele 28 move tabella (i + 1) to tabella (i) 29 end-perform 30 move servizio to tabella (numele). 31 EX-SHIFT-SX. EXIT SECTION.
Guarda solo cosa fa l'istruzione 12, che richiama la section (routine) di nome shift-dx tante volte per quante translazioni vuoi ottenere
la routine Shift-dx, quindi, non fa altro che spostare di un carattere verso destra il vettore, posizionando la prima cella con il valore dell'ultima.
Le istruzioni 9, 10, 11 servono solo ad impostare la tabella con i valori da 1 a n, in modo tale da poter verificare se il programma funziona o meno.
P.s. a differenza del C, il cobol non ha l'elemento 0 di una tabella, parte sempre da 1 fino a n.
Ciao.
@Umby: grazie per il codice!
Vedo che è abbastanza distante dal C++, sui cui verte ora la mia attenzione.
Il fatto che il cobol parte dall'un per arrivare ad N mi tranquillizza, non capisco infatti perché invece inglobare lo zero.
@ apatriarca:
Grazie per l'idea, ho scritto e gira.
All'inizio mi dava problemi perché da zero lo facevo arrivare ad $N$ (invece che N-1) e sparava numeri folli per la prima componente. Ora è ok.
Per completezza, il testo chiedeva anche di eseguire uno scambio nella direzione opposta (sinistra) in caso di inserimento di $k$ negativo.
Ho provveduto (e gira) mettendo un piccolo while all'inizio
Cioè dicendogli di andare $n-k$ posti avanti invece che k indietro.
Ma siccome $n-k$ non è a priori positivo, lo faccio diventare positivo facendolo saltare in avanti su elementi equivalenti modulo $N$.
Penso che più sintetico di così non potevo essere.
ps: A lezio mi sembra di aver sempre visto la variabile inizializzata ad 1. Quindi nessuna ragione per non partire da zero, solo abitudine (che penso cambierò, a sto punto).
Grazie ancora per la disponibilità, a presto!
@Umby: grazie per il codice!
Vedo che è abbastanza distante dal C++, sui cui verte ora la mia attenzione.
Il fatto che il cobol parte dall'un per arrivare ad N mi tranquillizza, non capisco infatti perché invece inglobare lo zero.
@ apatriarca:
Grazie per l'idea, ho scritto e gira.
All'inizio mi dava problemi perché da zero lo facevo arrivare ad $N$ (invece che N-1) e sparava numeri folli per la prima componente. Ora è ok.
Per completezza, il testo chiedeva anche di eseguire uno scambio nella direzione opposta (sinistra) in caso di inserimento di $k$ negativo.
Ho provveduto (e gira) mettendo un piccolo while all'inizio
int t=1; while (k<0) {k=N*t+k; t=t+1;}
Cioè dicendogli di andare $n-k$ posti avanti invece che k indietro.
Ma siccome $n-k$ non è a priori positivo, lo faccio diventare positivo facendolo saltare in avanti su elementi equivalenti modulo $N$.
Penso che più sintetico di così non potevo essere.
ps: A lezio mi sembra di aver sempre visto la variabile inizializzata ad 1. Quindi nessuna ragione per non partire da zero, solo abitudine (che penso cambierò, a sto punto).
Grazie ancora per la disponibilità, a presto!
Vediamo nel dettaglio il comportamento dell'operatore % in modo da sfruttare le sue proprietà per scrivere il codice.
% è il resto della divisione intera tra i due operandi, deve cioè sempre valere la relazione a == (a / b) * b + a % b. La divisione intera tra due numeri è la parte intera della divisione: il risultato viene cioè troncato verso lo zero. Se quindi il segno di a e b è lo stesso allora (a / b) * b <= a e a % b è positivo, mentre se il segno è diverso (a / b) * b >= a e a % b è negativo. Supponendo ora che b sia sempre positivo, avremo che a mod b = a % b se a >= 0 e a mod b = b + (a % b) se a < 0. Nel tuo codice N è sempre positiva mentre K può essere positivo o negativo ed è quindi sufficiente usare la versione corretta del modulo a seconda della situazione.
C'è infine un'ultima nota da fare sul tuo codice. Non è necessario calcolare la nuova posizione di tutti gli elementi, ma solo del primo. Infatti, il secondo elemento seguirà sempre il primo o, al massimo, passerà al primo posto. Una volta trovato il primo è quindi sufficiente inserire tutti i valori uno dopo l'altro usando l'operatore di resto per ritornare alla prima posizione. Una funzione che fa quello richiesto è la seguente:
% è il resto della divisione intera tra i due operandi, deve cioè sempre valere la relazione a == (a / b) * b + a % b. La divisione intera tra due numeri è la parte intera della divisione: il risultato viene cioè troncato verso lo zero. Se quindi il segno di a e b è lo stesso allora (a / b) * b <= a e a % b è positivo, mentre se il segno è diverso (a / b) * b >= a e a % b è negativo. Supponendo ora che b sia sempre positivo, avremo che a mod b = a % b se a >= 0 e a mod b = b + (a % b) se a < 0. Nel tuo codice N è sempre positiva mentre K può essere positivo o negativo ed è quindi sufficiente usare la versione corretta del modulo a seconda della situazione.
C'è infine un'ultima nota da fare sul tuo codice. Non è necessario calcolare la nuova posizione di tutti gli elementi, ma solo del primo. Infatti, il secondo elemento seguirà sempre il primo o, al massimo, passerà al primo posto. Una volta trovato il primo è quindi sufficiente inserire tutti i valori uno dopo l'altro usando l'operatore di resto per ritornare alla prima posizione. Una funzione che fa quello richiesto è la seguente:
void rotate(double *src, double *dest, int size, int k) { assert(src != NULL); assert(dest != NULL); int y0 = k < 0 ? size + k % size : k % size; // calcola la posizione iniziale for (int i = 0; i < size; ++i) { dest[(y0 + i) % size] = src[i]; } }
Perfetto, ora è più chiaro tutto.
Grazie per il consiglio di semplificazione del codice; ci tornerò sopra nel dettaglio quando inizierò a muovermi bene anche con le funzioni, che ancora non ho affrontato con rigore.
Grazie per la disponibilità allora, a presto in questa sezione!
Grazie per il consiglio di semplificazione del codice; ci tornerò sopra nel dettaglio quando inizierò a muovermi bene anche con le funzioni, che ancora non ho affrontato con rigore.
Grazie per la disponibilità allora, a presto in questa sezione!

Perdonatemi, riesumo il topic per una difficoltà.
Stave cercando di strutturare il programma scrivendolo mediante funzioni.
Vorrei capire bene i motivi del risultato folle che ottengo
Il codice è questo:
La funzione che non va è appunto l'ultima, quella incaricata di scambiare: le altre vanno bene.
Questa funzione tra l'altro l'ho scritta mediante la traccia del programma analogo senza funzioni, quello che ho scritto e che girava grazie ai vostri suggerimenti.
La funzione è questa
Esempio? Imponendo un vettore a due coordinate $(3,3)$, se gli chiedo di traslarmi le coordinate di 3 posti (cioè sempre (3,3) ottengo) mi restituisce ben 4 valori (il doppio, come in altri casi):
un 3 e altri due assurdi, come 1,62115e-307, di questo genere insomma.
Se qualcuno potesse farmi capire dove devo individuare l'errore, gliene sarei grado. Specialmente perché mi stampa il doppio delle cose che chiedo, sebbene il ciclo for arrivi fino a N (cioè 2) senza scorciatoie.
Grazie mille in anticipo, e scusate per le numerose richieste.
Ciao!
Stave cercando di strutturare il programma scrivendolo mediante funzioni.
Vorrei capire bene i motivi del risultato folle che ottengo
Il codice è questo:
#include<iostream> #include<math.h> using namespace std; const int size=50; typedef double vettore[50]; void control(int&); void insertVet(vettore, int); void scalaVet (int, vettore, int&); main() { int N; vettore v; cout<<"Digita il numero di componenti del vettore: N="; cin>> N; control(N); insertVet(v,N); int h; cout<<"\n\nDi quante posizioni devo traslare le componenti?\nh="; cin>> h; scalaVet(N, v, h); system("PAUSE"); return 0;}
La funzione che non va è appunto l'ultima, quella incaricata di scambiare: le altre vanno bene.
Questa funzione tra l'altro l'ho scritta mediante la traccia del programma analogo senza funzioni, quello che ho scritto e che girava grazie ai vostri suggerimenti.
La funzione è questa
void scalaVet(int N, vettore v, int &k) { int t=1; while (k<0) {k=N*t+k; t=t+1;} int m=0; vettore u; for(m; m<N; m++) { {u[(k+m)%N]=v[m];}; for (int l=0; l<N; l++) cout <<u[l]<<"\n\n";} }
Esempio? Imponendo un vettore a due coordinate $(3,3)$, se gli chiedo di traslarmi le coordinate di 3 posti (cioè sempre (3,3) ottengo) mi restituisce ben 4 valori (il doppio, come in altri casi):
un 3 e altri due assurdi, come 1,62115e-307, di questo genere insomma.
Se qualcuno potesse farmi capire dove devo individuare l'errore, gliene sarei grado. Specialmente perché mi stampa il doppio delle cose che chiedo, sebbene il ciclo for arrivi fino a N (cioè 2) senza scorciatoie.
Grazie mille in anticipo, e scusate per le numerose richieste.
Ciao!

Hai messo il ciclo di stampa all'interno dell'altro ciclo, quindi:
quando m è 0 copia un elemento da v a u, poi stampa tutti gli elementi di u
quando m è 1 copia un elemento da v a u, poi stampa tutti gli elementi di u
ecc..
quando m è 0 copia un elemento da v a u, poi stampa tutti gli elementi di u
quando m è 1 copia un elemento da v a u, poi stampa tutti gli elementi di u
ecc..
Ti ringrazio molto: ora ho separato i cicli, e dopo aver messo in ordine qualche altra cosetta gira.
Alla prossima, buon weekend!
Alla prossima, buon weekend!

Prima di tutto un piccolo commento sugli header dello standard C. Se inclusi nel modo classico del C, le loro funzioni vengono inserite nel namespace globale della tua applicazione. Per includerli nel namespace std come è il caso per quelle del C++, si devono includere aggiungendo una "c" all'inizio del nome e senza ".h":
#include
Come mai ci sono tutti quegli argomenti che sono passati per reference? Come mai permetti alle funzioni control e scalaVet di cambiare i valori che gli vengono passati?
scalaVet è un pessimo nome per quella funzione. Lo scalamento di un vettore è infatti un'operazione ben determinata e cioè la moltiplicazione di ogni elemento di un vettore per uno scalare. L'operazione effettuata nel tuo codice è invece normalmente chiamata rotazione (rotate in inglese). Avrebbe quindi più senso il nome rotateVec o qualcosa di simile.
La rotazione di un singolo vettore poteva essere fatta in due modi. Il primo, quello da te tentato, è quello di fare la rotazione scrivendo in un secondo vettore e poi ricopiarlo in quello originale in un ciclo separato. Il secondo è una rotazione in place che adesso cerco di mostrarti.
Il problema della rotazione in place è che per poter memorizzare soltanto un elemento è necessario eseguire la rotazione a cicli disgiunti. Considera ad esempio un array di 6 elementi e una rotazione di 2:
1. Il primo elemento finisce nel terzo, il terzo nel quinto e il quinto finisce a sua volta nel primo.
2. Il secondo elemento finsce nel quarto che finisce nel sesto che chiude il ciclo.
Nota che se hai calcolato il ciclo a partire da un indice i, il ciclo successivo lo puoi far partire a (i+1) a meno di aver già modificato tutti gli elementi. Questo metodo, anche se usa meno memoria, è potenzialmente più lento perché itera almeno una volta su tutto l'array per ogni ciclo. Ma dipende molto dalla dimensione dell'array, da k e dal costo dell'allocazione del blocco di memoria.
Per poter calcolare esattamente tutti i cicli si potrebbe far ricorso al MCD tra indice generatore ed n, ma è possibile farne a meno:
Non ho provato a compilarla ma dovrebbe funzionare. Come vedi, il codice è un po' più complicato di quello con copia.
Il C++ contiene una grossa quantità di algoritmi già disponibili includendo. Una delle funzioni disponibili è rotate che fa l'operazione desiderata in place, come la mia funzione. Ovviamente non è utilizzabile negli esercizi, ma nei programmi reali è molto utile. E' quindi bene sapere della sua esistenza.
#include
Come mai ci sono tutti quegli argomenti che sono passati per reference? Come mai permetti alle funzioni control e scalaVet di cambiare i valori che gli vengono passati?
scalaVet è un pessimo nome per quella funzione. Lo scalamento di un vettore è infatti un'operazione ben determinata e cioè la moltiplicazione di ogni elemento di un vettore per uno scalare. L'operazione effettuata nel tuo codice è invece normalmente chiamata rotazione (rotate in inglese). Avrebbe quindi più senso il nome rotateVec o qualcosa di simile.
La rotazione di un singolo vettore poteva essere fatta in due modi. Il primo, quello da te tentato, è quello di fare la rotazione scrivendo in un secondo vettore e poi ricopiarlo in quello originale in un ciclo separato. Il secondo è una rotazione in place che adesso cerco di mostrarti.
Il problema della rotazione in place è che per poter memorizzare soltanto un elemento è necessario eseguire la rotazione a cicli disgiunti. Considera ad esempio un array di 6 elementi e una rotazione di 2:
1. Il primo elemento finisce nel terzo, il terzo nel quinto e il quinto finisce a sua volta nel primo.
2. Il secondo elemento finsce nel quarto che finisce nel sesto che chiude il ciclo.
Nota che se hai calcolato il ciclo a partire da un indice i, il ciclo successivo lo puoi far partire a (i+1) a meno di aver già modificato tutti gli elementi. Questo metodo, anche se usa meno memoria, è potenzialmente più lento perché itera almeno una volta su tutto l'array per ogni ciclo. Ma dipende molto dalla dimensione dell'array, da k e dal costo dell'allocazione del blocco di memoria.
Per poter calcolare esattamente tutti i cicli si potrebbe far ricorso al MCD tra indice generatore ed n, ma è possibile farne a meno:
int rotate_in_place(int n, double *vec, int k) { if (n < 0 || 0 == vec) return 0; // errore nei parametri di input if (k == 0) return 1; // successo, non c'è niente da fare... // metodo veloce per calcolare il modulo, nota che potresti anche aggiungere // un if per assicurarti che venga fatto solo quando sia necessario. k %= n; if (k < 0) k += n; int c; // conta il numero di elementi già modificati int v; // l'indice dal quale parte il sottociclo for (c = 0, v = 0; c < n; ++v) { int i = v, j = v + k; int old = vec[j]; vec[j] = vec[i]; ++c; while (j != v) { i = j; j += k; if (j > n) j -= n; int tmp = old; old = vec[j]; vec[j] = tmp; ++c; } } return 1; // successo }
Non ho provato a compilarla ma dovrebbe funzionare. Come vedi, il codice è un po' più complicato di quello con copia.
Il C++ contiene una grossa quantità di algoritmi già disponibili includendo
Ciao apatriarca, scusa ma ho visto in ritardo il tuo post.
"Control" ho appurato che non va a dovere se non passo per riferimento, si verifica lo stesso fenomeno che denunciavo qua
https://www.matematicamente.it/forum/fun ... 48346.html
e che mi avete fatto risolvere.
C'è modo di rinunciare ad usare "&"? Se sì, perché farlo?
Per quanto riguarda la "scalavet" (a cui ho cambiato nome, per le osservazioni che mi hai fatto in seguito) ho in effetti provato a togliere la "&" e pare andare ugualmente.
Inizialmente l'avevo messa per questo motivo: siccome mi pare di ricordare che altrove, forse proprio tu, mi dicesti che la funzione modulo funziona solo con argomenti positivi, ci tenevo mano mano al fatto che $h$ rimanesse salvata dopo l'incremento, fino a che non diventa positiva.
Interessante la decomposizione per cicli; il codice sì mi torna più complicato, ora vedo di leggerlo bene.
Infatti non sapevo questa cosa.
Grazie mille per l'info e per tutte le dritte in generale.
A presto!
Come mai ci sono tutti quegli argomenti che sono passati per reference? Come mai permetti alle funzioni control e scalaVet di cambiare i valori che gli vengono passati?
"Control" ho appurato che non va a dovere se non passo per riferimento, si verifica lo stesso fenomeno che denunciavo qua
https://www.matematicamente.it/forum/fun ... 48346.html
e che mi avete fatto risolvere.
C'è modo di rinunciare ad usare "&"? Se sì, perché farlo?
Per quanto riguarda la "scalavet" (a cui ho cambiato nome, per le osservazioni che mi hai fatto in seguito) ho in effetti provato a togliere la "&" e pare andare ugualmente.
Inizialmente l'avevo messa per questo motivo: siccome mi pare di ricordare che altrove, forse proprio tu, mi dicesti che la funzione modulo funziona solo con argomenti positivi, ci tenevo mano mano al fatto che $h$ rimanesse salvata dopo l'incremento, fino a che non diventa positiva.
Interessante la decomposizione per cicli; il codice sì mi torna più complicato, ora vedo di leggerlo bene.
Il C++ contiene una grossa quantità di algoritmi già disponibili includendo. Una delle funzioni disponibili è rotate che fa l'operazione desiderata in place, come la mia funzione. Ovviamente non è utilizzabile negli esercizi, ma nei programmi reali è molto utile. E' quindi bene sapere della sua esistenza.
Infatti non sapevo questa cosa.
Grazie mille per l'info e per tutte le dritte in generale.
A presto!
Mi sono appena accorto di averti scritto il nome della libreria sbagliato. Devi includere con la h. Qui trovi maggiori informazioni.
Ciao,
Allora come regola principale tieni presente che in C tutti i parametri alle funzioni sono passati c.d. "per valore" ovvero per copia: la variabile o costante viene copiata sullo stack e viene incrementato lo stack pointer [lo sapevi già, vero?
]; per fare un esempio
se, poniamo, la variabile 'a' del codice programma chiamante è memorizzata in posizione 100, la variabile 'a' della funzione invece viene mantenuta in altra posizione, diciamo 200. Quindi modificando tale variabile 'a' nella funzione viene alterato ciò che è in posizione 200 e la variabile "originale" in posizione 100 non viene toccata.
Per poter alterare questo comportamento si utilizza il carattere & prima del nome variabile, il che corrisponde al valore "indirizzo di..."; in pratica non si passa il VALORE della variabile ma il suo indirizzo (si dice anche che si passa una variabile per riferimento):
In questo caso, viene passato il "valore dell'indirizzo della variabile a", ovverosia 100, alla funzione. E modificando il valore memorizzato "all'indirizzo 100" si modifica per l'appunto la variabile del codice chiamante.
In C++ è ancora più semplice, si può definire il passaggio per riferimento direttamente:
Questo evita l'uso di riferimenti (puntatori a...) e rende il codice estremamente più leggibile.
Per tornare alla tua domanda, normalmente si passa tutto per copia, ma se c'è bisogno di modificare il valore di una variabile passata ad una funzione si passa per riferimento.
Consiglio: cerca di definire bene lo scoping di tutto ciò che serve e mantieni il codice il più ordinato possibile; se devi alterare il valore di una variabile 'a' sulla base di un calcolo fatto da una funzione, due sono le soluzioni principali:
1) la variabile 'a' è globale - usa questo metodo quando ha senso che vi sia una certa variabile 'a' che mantiene un certo valore per tutta la durata del programma, ed in generale qualsiasi funzione vi deve poter accedere (per leggerla o scriverla); il termine "globale" dovrebbe esserti d'aiuto nella scelta
2) la variabile viene passata come valore di ritorno [ a=funct(a, b, c); ...]
Spero di esserti stato d'aiuto (e di non averti invece confuso di più le idee...)
"Steven":
Ciao apatriarca, scusa ma ho visto in ritardo il tuo post.
Come mai ci sono tutti quegli argomenti che sono passati per reference? Come mai permetti alle funzioni control e scalaVet di cambiare i valori che gli vengono passati?
"Control" ho appurato che non va a dovere se non passo per riferimento, si verifica lo stesso fenomeno che denunciavo qua
https://www.matematicamente.it/forum/fun ... 48346.html
e che mi avete fatto risolvere.
C'è modo di rinunciare ad usare "&"? Se sì, perché farlo?
Allora come regola principale tieni presente che in C tutti i parametri alle funzioni sono passati c.d. "per valore" ovvero per copia: la variabile o costante viene copiata sullo stack e viene incrementato lo stack pointer [lo sapevi già, vero?

int funct(int); int a, retval; // some code here... retval = funct(a); // . . . int funct(int a) { a=computeSomething(); // funct code here... }
se, poniamo, la variabile 'a' del codice programma chiamante è memorizzata in posizione 100, la variabile 'a' della funzione invece viene mantenuta in altra posizione, diciamo 200. Quindi modificando tale variabile 'a' nella funzione viene alterato ciò che è in posizione 200 e la variabile "originale" in posizione 100 non viene toccata.
Per poter alterare questo comportamento si utilizza il carattere & prima del nome variabile, il che corrisponde al valore "indirizzo di..."; in pratica non si passa il VALORE della variabile ma il suo indirizzo (si dice anche che si passa una variabile per riferimento):
int funct(int *); int a, retval; // some code here... retval = funct(&a); // . . . int funct(int *a) { *a=computeSomething(); // funct code here... }
In questo caso, viene passato il "valore dell'indirizzo della variabile a", ovverosia 100, alla funzione. E modificando il valore memorizzato "all'indirizzo 100" si modifica per l'appunto la variabile del codice chiamante.
In C++ è ancora più semplice, si può definire il passaggio per riferimento direttamente:
int funct(int &); int a, retval; // some code here... retval = funct(a); // . . . int funct(int &a) { a=computeSomething(); // funct code here... }
Questo evita l'uso di riferimenti (puntatori a...) e rende il codice estremamente più leggibile.
Per tornare alla tua domanda, normalmente si passa tutto per copia, ma se c'è bisogno di modificare il valore di una variabile passata ad una funzione si passa per riferimento.
Consiglio: cerca di definire bene lo scoping di tutto ciò che serve e mantieni il codice il più ordinato possibile; se devi alterare il valore di una variabile 'a' sulla base di un calcolo fatto da una funzione, due sono le soluzioni principali:
1) la variabile 'a' è globale - usa questo metodo quando ha senso che vi sia una certa variabile 'a' che mantiene un certo valore per tutta la durata del programma, ed in generale qualsiasi funzione vi deve poter accedere (per leggerla o scriverla); il termine "globale" dovrebbe esserti d'aiuto nella scelta

2) la variabile viene passata come valore di ritorno [ a=funct(a, b, c); ...]
Spero di esserti stato d'aiuto (e di non averti invece confuso di più le idee...)
Ciao Rggb
Ho letto, non conoscendo minimamente il C non psono in grado autonomamente di fare raffronti. Grazie per avermi mostrato questa prospettiva.
Tutt'altro, sei stato molto lineare.
Grazie per le info e la disponibilità, alla prossima!

Ho letto, non conoscendo minimamente il C non psono in grado autonomamente di fare raffronti. Grazie per avermi mostrato questa prospettiva.
"Rggb":
Spero di esserti stato d'aiuto (e di non averti invece confuso di più le idee...)
Tutt'altro, sei stato molto lineare.
Grazie per le info e la disponibilità, alla prossima!
