Oppure

Loading
17/10/12 16:11
Tommaso95
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:
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 :(
aaa
17/10/12 17:58
Poggi Marco
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:
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.
aaa
17/10/12 18:06
Tommaso95
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?

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 17/10/12 18:18
aaa
17/10/12 19:46
Poggi Marco
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:
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:
begin
  clrScr;
  carica_dati(ele);
  writeln('Vettore originale ');
  stampa_dati(ele);
  writeln;
  controllo_doppioni(ele);
  writeln('Eliminazione dei doppi ');
  stampa_dati(ele);
  readln;
end.
aaa
17/10/12 21:24
Tommaso95
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à
aaa
17/10/12 21:35
Goblin
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:
  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
  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
17/10/12 22:48
Poggi Marco
@ 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 17/10/12 22:50
aaa
18/10/12 17:55
Tommaso95
@ 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 ;)
aaa