Numeri casuali e Segmentation fault in C - [Risolto]

Forum dedicato alla programmazione.

Moderatore: Staff

Regole del forum
1) Citare in modo preciso il linguaggio di programmazione usato.
2) Se possibile portare un esempio del risultato atteso.
3) Leggere attentamente le risposte ricevute.
4) Scrivere i messaggi con il colore di default, evitare altri colori.
5) Scrivere in Italiano o in Inglese, se possibile grammaticalmente corretto, evitate stili di scrittura poco chiari, quindi nessuna abbreviazione tipo telegramma o scrittura stile SMS o CHAT.
6) Appena registrati è consigliato presentarsi nel forum dedicato.

La non osservanza delle regole porta a provvedimenti di vari tipo da parte dello staff, in particolare la non osservanza della regola 5 porta alla cancellazione del post e alla segnalazione dell'utente. In caso di recidività l'utente rischia il ban temporaneo.
Rispondi
Avatar utente
SIV
Linux 3.x
Linux 3.x
Messaggi: 921
Iscritto il: mer 25 apr 2007, 14:07

Numeri casuali e Segmentation fault in C - [Risolto]

Messaggio da SIV »

Ragazzi stavo facendo qualche esercizio in C.

Devo estrarre un numero casuale tratto dal gruppo -> 6,10,14,18,22 senza usare particolari funzioni e neanche degli array, solo la funzione (s)rand e dei controlli.

Ho scritto questo:

Codice: Seleziona tutto

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

int check();
int i;

int main(){

int number=0;
number=check();
printf("Numero estratto: %d\n", number);

return 0;

}

int check(){

srand(time(NULL));
i = 6+rand()%22;

if (i==6 || i==10 || i==14 || i==18 || i==22){return i;}

else {return check();}

}
Però a volte va in seg fault. Ecco l'output:

Codice: Seleziona tutto

muller:~/temp# gcc 5.14-c.c 
muller:~/temp# ./a.out      
Numero estratto: 22
muller:~/temp# ./a.out 
Numero estratto: 18
muller:~/temp# ./a.out 
Numero estratto: 18
muller:~/temp# ./a.out 
Numero estratto: 22
muller:~/temp# ./a.out 
Segmentation fault
muller:~/temp# ./a.out 
Numero estratto: 14
..
muller:~/temp# ./a.out 
Segmentation fault
muller:~/temp# ./a.out 
Segmentation fault
...
Ho come l'impressione che se il numero estratto non sia tra quelli elencati e quindi vada all'else nella funzione check, vada in seg fault.

:-k :-k
Ultima modifica di SIV il ven 3 lug 2009, 12:17, modificato 1 volta in totale.

Avatar utente
d4z_c0nf
Packager
Packager
Messaggi: 1296
Iscritto il: mar 14 mar 2006, 18:07
Nome Cognome: Rocco Aliberti
Slackware: 14.2-current64
Kernel: 4.14.73
Desktop: awesomeWM
Località: Pinerolo

Re: Numeri casuali e Segmentation fault - C

Messaggio da d4z_c0nf »

Perchè non puoi usare gli array?
In ogni caso anche non usando gli array come "struttura" puoi simularli, chi te lo vieta?

Codice: Seleziona tutto

 switch( i )
     {
        case 0:	return 6;
        case 1:	return 10;
        // ecc ecc
     }
Il problema del segfault può essere che "ricorre" troppo, visto che tra 0 e 22 ci sono 23 numeri e beccare giusto uno di quei sei non è facilissimo. Elimina la ricorsione insomma, anche perchè mi pare eccessivo usarla in un caso come questo...
rock

Avatar utente
SIV
Linux 3.x
Linux 3.x
Messaggi: 921
Iscritto il: mer 25 apr 2007, 14:07

Re: Numeri casuali e Segmentation fault - C

Messaggio da SIV »

Per gli array è proprio l'esercizio che lo richiede.

Comunque sia, se elimino la ricorsione, come faccio a scrivere una funzione che estrae un numero a caso e se non è nel "gruppo" di rifare la selezione?

Avatar utente
GioPower
Packager
Packager
Messaggi: 46
Iscritto il: lun 13 ott 2008, 14:26
Nome Cognome: Luca Giona
Slackware: 13 x86_64
Kernel: 2.6.29
Desktop: xfce

Re: Numeri casuali e Segmentation fault - C

Messaggio da GioPower »

Guardando i numeri che devi ritornare, ho notato che rispettano la regola che:

Codice: Seleziona tutto

num =  6 + ( x * 4 )
dove num e' il numero di ritorno e x e' un numero casuale compreso tra [0,4].

Quindi io farei una cosa cosi:

Codice: Seleziona tutto

int main(...)
{
  //cose varie
  //...

  int num = rand(...) % 5;
  num *= 4;
  num += 6;
  printf("Numero estratto: %d\n", num);

  //altre cose varie
  //...
}
Non so se una soluzione del genere possa valere per l'esercizio in questione.

Avatar utente
FireEater
Linux 3.x
Linux 3.x
Messaggi: 508
Iscritto il: sab 5 feb 2005, 0:00
Nome Cognome: Giuseppe M.
Slackware: Current
Kernel: 2.6.32.7-smp
Desktop: kde 4.3.4
Località: Cagliari <---> Torino

Re: Numeri casuali e Segmentation fault - C

Messaggio da FireEater »

Il segmentation fault è probabilmente dovuto ad uno stack overflow. Al contrario di come si potrebbe immaginare la programmazione ricorsiva è computazionalmente molto più pesante rispetto a quella iterativa. Questo succede perchè il contesto della funzione ricorsiva viene caricato sullo stack ad ogni chiamata.

La soluzione riportata da GioPower è senza dubbio la migliore e probabilmente è quella che ha pensato chi ha scritto l'esercizio.

Ad ogni modo una possibile riscrittura di quella funzione ricorsiva è:
sorvolando sul i = 6+rand()%22; che non è proprio l'ideale dato che estrae da 6 a 27...

Codice: Seleziona tutto

int check(){
for (int i = 6+rand()%22; (i!=6 && i!=10 && i!=14 && i!=18 && i!=22); i =  6+rand()%22;)
__noop; // o {}

return i;
}
Il random seed va inizializzato nel main, farlo all'interno della funzione in questo caso non serve.

FireEeater

Avatar utente
SIV
Linux 3.x
Linux 3.x
Messaggi: 921
Iscritto il: mer 25 apr 2007, 14:07

Re: Numeri casuali e Segmentation fault - C

Messaggio da SIV »

Ok ragazzi grazie a tutti.

- Sì sicuramente la soluzione scritta GioPower è quella pensata dallo scrittore.
- FireEater, potresti spiegarmi meglio la funzione check che hai scritto? :thumbright:

Avatar utente
FireEater
Linux 3.x
Linux 3.x
Messaggi: 508
Iscritto il: sab 5 feb 2005, 0:00
Nome Cognome: Giuseppe M.
Slackware: Current
Kernel: 2.6.32.7-smp
Desktop: kde 4.3.4
Località: Cagliari <---> Torino

Re: Numeri casuali e Segmentation fault - C

Messaggio da FireEater »

Questo codice è equivalente, in italiano si potrebbe dire: Fintantoché i è diverso da uno di quei numeri(6,10,14,18,22) estrai un altro numero. Quando è i uguale esce dal ciclo e ritorna il numero presente in i.

Codice: Seleziona tutto

int check(){

int i = 6+rand()%22;
while (i!=6 && i!=10 && i!=14 && i!=18 && i!=22)
{
 i =  6+rand()%22;
}
return i;
}
__noop; significa no operation e serve a non fare nulla durante il ciclo for, le parentesi graffe aperte e chiuse sono la stessa cosa.

OK? :)

Avatar utente
SIV
Linux 3.x
Linux 3.x
Messaggi: 921
Iscritto il: mer 25 apr 2007, 14:07

Re: Numeri casuali e Segmentation fault - C

Messaggio da SIV »

OK grazie FireEater, con il ciclo while ho capito il senso ed ho capito anche il ciclo for di prima. :D

Grazie a tutti :thumbright: :thumbright:

Rispondi