Pagina 1 di 1

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

Inviato: venerdì 16 maggio 2014, 18:13
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

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

Inviato: venerdì 16 maggio 2014, 18:22
da vaeVictis
Puoi postare un codice minimale che compili e riproduca il problema?
Grazie.

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

Inviato: venerdì 16 maggio 2014, 18:36
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

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

Inviato: venerdì 16 maggio 2014, 19:17
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.

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

Inviato: venerdì 16 maggio 2014, 19:19
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

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

Inviato: venerdì 16 maggio 2014, 20:11
da Fed10
Abbiamo risolto con l'accoppiata fgets() + atoi()
Grazie mille a tutti :)

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

Inviato: sabato 17 maggio 2014, 11:08
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]

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

Inviato: sabato 17 maggio 2014, 13:28
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)