printf scanf %d - нули для всех кроме последнего - как исправить - несколько значений подряд
Primary tabs
Forums:
Почему если вводить три единицы - для двух первых значений будут напечатаны нули??
#include < stdio.h >
char main (void)
{
char banana=1;
char choc=1;
char apple=1;
printf("How many bananas do you need?\r\n");
scanf(" %d",&banana);
printf("How many bars of chocolate do you need?\r\n");
scanf(" %d",&choc);
printf("How many apples do you need?\r\n");
scanf(" %d",&apple);
printf("Total:\r\n");
printf("%-15s: %d\r\n","Bananas",banana);
printf("%-15s: %d\r\n","Choc.Bars",choc);
printf("%-15s: %d\r\n","Apples",apple);
return;
}
То есть что-то типа:
How many bananas do you need? How many bars of chocolate do you need? How many apples do you need? Total: Bananas : 0 Choc.Bars : 0 Apples : 1
- Log in to post comments
- 8239 reads
math2
Sat, 07/18/2015 - 00:48
Permalink
Если компилировать эту
Если компилировать эту программу компилятором
cc (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4
то такого эффекта не наблюдается. Однако при этом cc выдаёт следующие предупреждения
prog.c: In function ‘main’: prog.c:8:2: warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘char *’ [-Wformat=] scanf(" %d",&banana); ^ prog.c:10:5: warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘char *’ [-Wformat=] scanf(" %d",&choc); ^ prog.c:12:5: warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘char *’ [-Wformat=] scanf(" %d",&apple);Но если компилировать эту программу более старым компилятором
cc 2.95.4,
то для первых двух переменных будут печататься нули. Почему?
Посмотрим по каким адресам загружаются переменные
char banana=1; char choc=1; char apple=1;Используем для этого отладчим gdb
Строки 32, 34 и 36 показывают, что наши переменные размещаются в памяти последовательно:
В машинах архитектуры x86 младший байт целочисленных типов
(например, 32 разрядные int в си, или dword в ассемблере) размещается по младшему адресу.
Адрес переменной в Си есть адрес её младшего байта.
Переменная типа char занимает в памяти один байт, а переменная типа int занимает 4 байта.
%d указывает на тип int, то есть на 4 байта.
Если будет выполнена строка
scanf(" %d",&banana);
то в память начиная с адреса 0xbffff6f7, будут записаны 4 байта.
Это значит, что будут изменены ячейки по адресам
После выполнения строки
scanf(" %d",&choc);в память, начиная с адреса 0xbffff6f6, будут записаны 4 байта.
Это значит, что будут изменены ячейки по адресам
Получается, что если мы будем вводить, например 12, то младший байт того значения типа int,
которое будет записываться начиная с адреса 0xbffff6f6 (это адрес переменной banana),
будет содержать значение 12, а старшие три байта --- нули.
Поэтому теперь байт по адресу &banana имеет значение ноль.
После выполнения строки
scanf(" %d",&apple);
в память, начиная с адреса 0xbffff6f5, будут записаны 4 байта.
Это значит, что будут изменены ячейки по адресам
0xbffff6f9
0xbffff6f8
0xbffff6f7
0xbffff6f6
Получается, что мы уничтожаем и значение переменной choc.
Тем не менее, когда будет выполняться строка
printf("%-15s: %d\r\n","Apples",apple);будет выводиться значение именно одного байта по адресу &apple.
В обоих системах, и в старой с компилятором cc 2.95.4, и в новой с cc (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4, это значение, кажется, будет интерпретировано как дополнительный код.
Так как когда я ввожу для apple значение 128, то получаю в младшем байте
1000 0000,
а программа выводит минус 128. Это очень похоже на дополнительный код.
Кстати, компилятор cc 2.95.4 выдаёт ещё такое предупреждение:
vedro-compota
Sat, 07/18/2015 - 10:08
Permalink
классный ответ)
классный ответ)
_____________
матфак вгу и остальная классика =)
math2
Sat, 07/18/2015 - 00:49
Permalink
Нужно изменить тип переменных
Нужно изменить тип переменных с char на int.