Tommaso95 (Normal User)
Newbie
Messaggi: 17
Iscritto: 17/10/2012
|
Ciao a tutti, sono nuovo e sto imparando a programmare con il Pascal sia a scuola sia per conto mio.
Ho creato qualche programma più o meno complesso (tutti relativamente facili alla fine) ma non riesco a saltarne fuori con questo che all'apparenza è semplicissimo ma ha un "pezzo" che mi crea problemi.
In pratica devo:
- Creare un array con 100 elementi
- Riempirlo con numeri da 1 a 100
- Controllare la presenza di eventuali doppioni e se ci sono sostituirli
- Stampare l'array.
Il codice che ho creato fino adesso è questo:
Codice sorgente - presumibilmente Delphi |
program test; uses crt; type tab = array[1..100] of integer; var ele:tab; procedure carica_dati(var ele:tab); var a:byte; begin randomize; for a:=1 to 100 do ele[a]:=random(100)+1; end; procedure controllo_doppioni(var ele:tab); var a,pos:byte; begin for a:=1 to 100 do begin repeat pos:=2; if (ele[a]<>ele[pos]) and (pos<=100) then begin pos:=pos+1; end else ele[pos]:=random(100)+1; until pos>100; end; end; procedure stampa_dati(ele:tab); var a:byte; begin for a:=1 to 100 do Write(ele[a]:5); end; begin clrscr; carica_dati(ele); controllo_doppioni(ele); stampa_dati(ele); readln; end.
|
I problemi\domande che ho sono due:
1) Perchè la procedura controllo non funziona? Mi interessa sapere più che altro concettualmente che erroe ho fatto
2) Perchè il nostro prof ha detto che i parametri che mettiamo tra parentesi dopo il nome della procedura possono essere o di input\output (se hanno il var) o solo di input se non lo hanno ma in ogni caso mi stampano l'array ? Se non si è capita questa domanda, perchè anche se tolgo il var mi stampa l'array? In teoria non è solo di input?
Grazie a tutti.
P.S. Purtroppo da questo primo mesi di informatica a scuola ho notato che è una materia ancora tralasciata da molti. In classe siamo solo in 3-4 a sapere qualcosa, gli altri non sanno nemmeno a cosa serve read o write
|
|
Poggi Marco (Member)
Guru
Messaggi: 969
Iscritto: 05/01/2010
|
Ciao!
La funzione non funziona essenzialmente per due motivi; alla variabile pos viene assegnato 1 all' inizio del loop interno, causando un ciclo infinito. Quando si trova un' uguaglianza, gli indici a e pos vanno reinizializzati; quando si modifica un valore, si deve ricontrollare tutto l' array.
l' identificatore var serve ad identificare in che modo avviene il passaggio delle variabili alle funzioni.
Senza -> il passaggio avviene " per valore "; ovvero si crea una copia della variabile.
Con var -> il passaggio avviene " per indirizzo "; qualsiasi modifica alla variabile locale, permane a quella indicata alla chiamata della funzione.
Ecco un esempio:
Codice sorgente - presumibilmente Delphi |
program passaggio; var a:integer; procedure passaggioPerValore(x:integer); begin x:=x+8; // la modifica è locale end; procedure passaggioPerIndirizzo(var x:integer); begin x:=x+8; // modifica permanente end; begin a:=5; writeln('a vale ',a); passaggioPerValore(a); writeln('a vale ',a); passaggioPerIndirizzo(a); writeln('a vale ',a); readln; end.
|
|
|
Tommaso95 (Normal User)
Newbie
Messaggi: 17
Iscritto: 17/10/2012
|
1) Ok, quindi dovrei prima dichiarare pos fuori dal reapeat. Per reinizializzare pos e a come posso fare?
2) Penso di avere capito. Nel mio programma perchè mi stampa l'array in ogni caso anche se tolgo il var?
Codice sorgente - presumibilmente Delphi |
program test; uses crt; type tab = array[1..100] of integer; var ele:tab; procedure carica_dati(var ele:tab); var a:byte; begin randomize; for a:=1 to 100 do ele[a]:=random(100)+1; end; procedure controllo_doppioni(var ele:tab); var a,pos:byte; begin for a:=1 to 100 do begin pos:=2; repeat if (ele[a]<>ele[pos]) and (pos<=100) then begin pos:=pos+1; end else begin ele[pos]:=random(100)+1; pos:=1; a:=1; end; until pos>100; end; end; procedure stampa_dati(ele:tab); var a:byte; begin for a:=1 to 100 do Write(ele[a]:5); end; begin clrscr; carica_dati(ele); controllo_doppioni(ele); stampa_dati(ele); readln; end.
|
Ultima modifica effettuata da Tommaso95 il 17/10/2012 alle 20:18 |
|
Poggi Marco (Member)
Guru
Messaggi: 969
Iscritto: 05/01/2010
|
1) Prima di inizializzare pos, devi racchiudere il ciclo for tra un begin e un end, altrimenti verrà assegnato 1 a pos per cento volte, e successivamente eseguito il ciclo repeat una volta.
Ad esempio:
Codice sorgente - presumibilmente Delphi |
procedure controllo_doppioni(var ele:tab); var a,pos:byte; begin a:=1; while a<100 do begin pos:=a+1; // inizializzo pos all' inizio del ciclo esterno repeat if (ele[a]<>ele[pos]) or (pos=a) then // mi accerto che gli indici siano diversi begin pos:=pos+1; end else begin ele[pos]:=random(100)+1; pos:=2; a:=1; end; until pos>100; a:=a+1; end; end;
|
2) La funzione stampa funziona comunque con var o senza, perché in entrambi i casi riceve i valori del vettore; cambia solo la modalità di ricezione.
Prova a togliere var da controllo_doppioni, e richiamare le funzioni nel seguente modo:
Codice sorgente - presumibilmente Pascal |
begin clrScr; carica_dati(ele); writeln('Vettore originale '); stampa_dati(ele); writeln; controllo_doppioni(ele); writeln('Eliminazione dei doppi '); stampa_dati(ele); readln; end.
|
|
|
Tommaso95 (Normal User)
Newbie
Messaggi: 17
Iscritto: 17/10/2012
|
Grazie, ho capito quasi tutto. Solo due domande:
1) Perchè metti (pos=a)? In teoria non sono sempre diversi?
2) Perchè alla fine metti a:=a+1; ? A cosa si riferisce?
Grazie mille ancora per al tua disponibilità
|
|
Goblin (Member)
Expert
Messaggi: 375
Iscritto: 02/02/2011
|
Postato originariamente da Tommaso95:
In pratica devo:
- Creare un array con 100 elementi
- Riempirlo con numeri da 1 a 100
- Controllare la presenza di eventuali doppioni e se ci sono sostituirli
- Stampare l'array.
|
Io voglio darti una soluzione alternativa nel caso in cui il punto 4 potrebbe essere interpretato come:
"evitare la presenza di doppioni nell'array"
costruiamo un array di comodo con dentro la serie di numeri da 1 a 100:
Codice sorgente - presumibilmente Pascal |
for x:= 1 to 100 do aDummy[x] := x;
|
estraiamo 1 numero a caso andado a pescare nell'array di comodo il relativo valore e settiamo il valore dell'array di comodo a -1, nel caso in cui il valore dell'array di comodo è già a -1 vuol dire che il relativo valore è già stato estratto dunque ripetiamo l'estrazione
Codice sorgente - presumibilmente Delphi |
nciclo:=1; While nCiclo<=100 do begin nEstratto := random(100)+1; if aDummy[nEstratto] <> -1 then begin ele[nCiclo] := aDummy[nEstratto]; aDummy[nEstratto] := -1; inc(nCiclo); end; end;
|
In questo modo i tempi si riducono drasticamente, da una stima fatta "al volo" si dovrebbero risparmiare circa 15-20000 cicli di estrazione
Ibis redibis non morieris in bello |
|
Poggi Marco (Member)
Guru
Messaggi: 969
Iscritto: 05/01/2010
|
@ Tommaso95:
1)In effetti, la condizione " pos=a " risulta superflua. E' stato un eccesso di controllo.
Me ne sono reso conto solo ora...
2) L' istruzione " a := a+1 ; " serve ad incrementare l' indice del ciclo esterno; ho sostituito il ciclo for con un ciclo while per ragioni di stile. Mi sembrava poco elegante maneggiare direttamente la variabile gestita dal for.
@ Goblin:
Esiste un metodo ancora più efficiente:
- Creo un vettore con tutti gli elementi che compaiono solo una volta.
( tutti i numeri da 1 a 100 in ordine crescente )
- Imposto in ciclo che esamini ogni posizione del vettore.
- Estraggo un numero casuale tra l' indice del ciclo ed il numero di elementi del vettore.
- Scambio i valori che si trovano in posizione dell' indice del ciclo e del numero estratto.
Ultima modifica effettuata da Poggi Marco il 18/10/2012 alle 0:50 |
|
Tommaso95 (Normal User)
Newbie
Messaggi: 17
Iscritto: 17/10/2012
|
@ Goblin, Logicamente ho capito cosa vuoi fare, ma non ho ben capito cosa metti dentro aDummy e come fa ad essere uguale a -1.
@Marco Grazie ancora, ho capito perfettamente il programma adesso.
Se per caso hai già sotto mano il codice riguardante l'algoritmo di cui hai parlato, riusciresti a postarlo che non ho capito benissimo dalla descrizione? Se non hai il codice fa niente
|
|
Poggi Marco (Member)
Guru
Messaggi: 969
Iscritto: 05/01/2010
|
L' idea è impostare un ciclo che ad ogni iterazione, generi un numero sul vettore.
Quindi predispongo l' array
Codice sorgente - presumibilmente Delphi |
procedure precarica(var ele:tab; fine:integer); (* fine è la dimensione del vettore *) var i:integer; begin for i:=1 to fine do begin ele[i]:=i; end; end;
|
Casualizzo il vettore:
Codice sorgente - presumibilmente Delphi |
procedure casualizza_vettore(var ele:tab; fine:integer); var i,estratto,scambio:integer; begin precarica(ele, fine); for i:=1 to fine-1 do begin // genero un numero casuale che abbia un range uguale ai cicli ancora da effettuare, e parta da i+1 estratto:=i+1+random(fine-i); // lavoro sulle posizioni del vettore scambio:=ele[i]; ele[i]:=ele[estratto]; ele[estratto]:=scambio; end; end;
|
Ultima modifica effettuata da Poggi Marco il 18/10/2012 alle 22:35 |
|