[RISOLTO][C] Azzeramento variabile letta con scanf()

Linguaggi di programmazione: php, perl, python, C, bash e tutti gli altri.
Fed10
Prode Principiante
Messaggi: 83
Iscrizione: martedì 11 marzo 2014, 18:17
Desktop: Unity
Distribuzione: Ubuntu 14.10

[RISOLTO][C] Azzeramento variabile letta con scanf()

Messaggio da Fed10 »

Buonasera,
implementando in C algoritmi per un esami di programmazione all'università, mi sono imbattuto in un problema insolito.
In questo codice:

Codice: Seleziona tutto

char k;
unsigned int Val;

scanf("%d", &Val);
_Fflush();

scanf("%d", &k);
_Fflush();

...
se stampo le variabili, una volta lette, la prima variabile (Val) varrà sempre zero, mentre la seconda avrà il valore inserito.
Se, invece, provo ad invertire gli scanf, leggendo, quindi, prima la variabile k e poi la variabile Val, non incorro in questo problema e le variabili avranno il valore assegnato.

Grazie in anticipo,
Fed10
Ultima modifica di Fed10 il venerdì 16 maggio 2014, 20:12, modificato 1 volta in totale.
Avatar utente
vaeVictis
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 4703
Iscrizione: venerdì 27 luglio 2012, 17:58
Desktop: Gnome
Distribuzione: Ubuntu 20.04 64bit

Re: [C] Azzeramento variabile letta con scanf()

Messaggio da vaeVictis »

Puoi postare un codice minimale che compili e riproduca il problema?
Grazie.
Pirates arrrrrrrrrrr awesome!!!
«I fear not the man who has practiced 10000 kicks once,
but I fear the man who has practiced one kick 10000 times.»
Fed10
Prode Principiante
Messaggi: 83
Iscrizione: martedì 11 marzo 2014, 18:17
Desktop: Unity
Distribuzione: Ubuntu 14.10

Re: [C] Azzeramento variabile letta con scanf()

Messaggio da Fed10 »

Questo è il codice

Codice: Seleziona tutto

#include <stdio.h>

void main()
{   char k;
    unsigned int Val;

    scanf("%d", &Val);
    _Fflush();

    scanf("%d", &k);
    _Fflush();

   printf("Val:%d, K:%d \n\n", Val, k);
}

void _Fflush(void)
{ int c;

  do{ c = getchar();
    }while (c != '\n' && c != EOF);
}
Codice dà problemi compilato da Codeblocks con compilatore GCC e sistema operativo Linux Mint 16.
Grazie
Avatar utente
vbextreme
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1214
Iscrizione: domenica 12 gennaio 2014, 14:06
Desktop: lxde
Distribuzione: xubuntu 14.10

Re: [C] Azzeramento variabile letta con scanf()

Messaggio da vbextreme »

la variabile k é un char e quindi non puo essere letta dalla scanf con %d ma va usato %c.
Io consiglio sempre l'accoppiata fgets e atoi.
Easy framework per il linguaggio C.
vbextreme hack your life
DavideDaSerra
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 349
Iscrizione: domenica 15 febbraio 2009, 15:26
Desktop: xubuntu
Distribuzione: Ubuntu12.10 x86_64
Località: Da qualche parte in quel di Modena

Re: [C] Azzeramento variabile letta con scanf()

Messaggio da DavideDaSerra »

In effetti il problema potrebbe essere quello suggerito.

PS a me il tuo esempio compila e funziona in entrambi i casi, compilato con gcc ed eseguito su raspbian
Fed10
Prode Principiante
Messaggi: 83
Iscrizione: martedì 11 marzo 2014, 18:17
Desktop: Unity
Distribuzione: Ubuntu 14.10

Re: [C] Azzeramento variabile letta con scanf()

Messaggio da Fed10 »

Abbiamo risolto con l'accoppiata fgets() + atoi()
Grazie mille a tutti :)
Avatar utente
vbextreme
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1214
Iscrizione: domenica 12 gennaio 2014, 14:06
Desktop: lxde
Distribuzione: xubuntu 14.10

Re: [RISOLTO][C] Azzeramento variabile letta con scanf()

Messaggio da vbextreme »

In effetti il problema potrebbe essere quello suggerito.
la scanf con il parametro %d si aspetta 4 byte, passandogli un solo byte dove andrà a scrivere i restanti 3 byte? semplice nella memoria adiacente che in questo case setta a 0 la variabile adiacente. In altri casi l'errore potrebbe rivelarsi di difficile comprensione.
Il suddetto errore viene poi ben spiegato dal compilatore con il seguente warning:
warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘char *’ [-Wformat=]
compilato con gcc ed eseguito su raspbian
Presumo tu abbia una scheda con architettura arm e quindi la compilazione sarà completamente diversa e porterà dunque ad errori diversi.Questo perchè i comandi assembly dell'arm(risc) sono completamente diversi dai comandi assembly di un x86(cisc/risc) effettuando dei passaggi diversi si otterranno diveri errori che in quel caso potranno essere ancora piu difficile da trovare.
Abbiamo risolto con l'accoppiata fgets() + atoi()
Perfetto io ti consoglierei ancora due cose,primo è implementare una corretta funzione gets quale ad esempio:

Codice: Seleziona tutto

char* con_gets(char* d,int max)
{
    char* st = d;
    int c;
    while ( (c = getchar()) != EOF && c != '\n' && --max > 0 ) *d++ = c;
    *d = '\0';
    return st;
}
Questa funzione ti toglierà quell'odioso '\n' che riporta la fgets,praticamente è la gets dello standard ma priva del bug di buffer overflow.
Secondo la funzione main DEVE ritornare un int quindi è "int main()".
Il parametro di ritorno viene memorizzato nel registro "eax" quindi una funzione che esamina il parametro di ritorno di una funzione non farà altro che leggere tale registro,ma se tu utilizzi void non essegni niente a eax che conterrà dunque un valore casuale dato dall'ultimo utilizzo del suddetto registro,restituendo dunque un valore errato alla funzione chiamante.
Naturalmente il ritorno del valore della funzione main passa attraverso al kernel linux ma questo è un dettaglio meno importante,perchè tanto lui non lo analizza,ma permette solo ad una applicazione estrna di accedervi tramite apposite system call.
Naturalmente anche questo è un warning del compilatore
warning: return type of ‘main’ is not ‘int’ [-Wmain]
Easy framework per il linguaggio C.
vbextreme hack your life
ixamit
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 499
Iscrizione: giovedì 14 novembre 2013, 10:16

Re: [RISOLTO][C] Azzeramento variabile letta con scanf()

Messaggio da ixamit »

Bisogna prestare attenzione a questo genere di errori perche' sono nozioni elementari dell' hacking.
Per meglio comprendere la pericolosità:

Codice: Seleziona tutto

max@studio:/tmp$ gcc -g foo.c
max@studio:/tmp$ gdb -q ./a.out 
Reading symbols from /tmp/a.out...done.
(gdb) l
1	#include <stdio.h>
2	
3	int main ()
4	{
5	    int a=0;
6	    char b;
7	
8	    scanf ("%d",&b);
9	    printf ("%d\n",a);
10	
(gdb) b 9
Breakpoint 1 at 0x4005a1: file foo.c, line 9.
(gdb) r
Starting program: /tmp/a.out 
256

Breakpoint 1, main () at foo.c:9
9	    printf ("%d\n",a);
(gdb) x /5xb &b
0x7fffffffe2db:	0x00	0x01	0x00	0x00	0x00
(gdb) print a
$1 = 1
(gdb) 

Scrivi risposta

Ritorna a “Programmazione”

Chi c’è in linea

Visualizzano questa sezione: 0 utenti iscritti e 4 ospiti