1
1

Изучаю Си, помогите решить проблему

Вот мой код:

#include <stdio.h>
#include <Windows.h>

int main(){
    int a, b, c;
    printf("Enter 1 value:");
    scanf("%d", &a);
    printf("\nEnter 2 value:");
    scanf("%d", &b);
    printf("\nEnter action you want to do with entered values[+,-,/,*]");
    scanf("%d", &c);

    switch(c) {
    case '+':
        printf("%d", a+b);
        break;
    case '-':
        printf("%d", a-b);
        break;
    case '*':
        printf("%d", a * b);
        break;
    case '/': 
        printf("%d", a/b);
        break;
    default:
        printf("\nEntered operator is not valid");
        return main();
    }

    system("PAUSE");
    return 0;
}

задан 23 Янв 14:35

изменен 23 Янв 22:47

Deleted's gravatar image


10327

1

Могу поспорить, второе значение тоже вводится неправильно, потому что вы не выбираете \n из входного потока.

(23 Янв 14:45) VladD

@VladD, при правильных данных (числа) все OK. scanf() писали достаточно прагматичные люди, он (кроме формата %c) пропускает пробелы, табуляции, ньюлайны и т.п.

Вот при ошибке форматного ввода он оставляет символ, на котором преобразование "сломалось" в потоке. И этот символ надо убирать.

На практике надежней всего просто прочесть поток до конца строки (включительно) или просто организовать построчный ввод с разбором строк в памяти.

(23 Янв 16:07) avp

@avp: Хм, в C++ не так :-) Тогда проблема в типа аргумента, да.

(23 Янв 16:42) VladD
1

@VladD, по поводу типа для c (нужно char, а не int с заменой %d на %c) ему уже @brightside90 написал.

Но это будет работать только для ввода операции без пробелов между ней и вторым операндом.

--

А что Вы имели в виду, когда написали, что в С++ не так? cin >> ?

--

Вообще-то, если не заморачиваться с проверками, то ввод операции (в формате ТС) можно написать так

 char c, strop[10];
 scanf ("%s", strop); c = strop[0];
(23 Янв 16:55) avp

@avp: Угу. cin >> (который является рекомендованным методом ввода с консоли в C++) не пропускает \n.


Нуууууу... strop[10] + scanf == buffer overflow == exploit. Вы же сами написали fgets.

(23 Янв 17:01) VladD

@VladD, exploit (а скорее segmentation fault или что-то еще в таком духе) -- для обучения это в самый раз.

--

А у меня (g++ в xubuntu (думаю на других будет то же самое)) замечательно пропускает. Вот все остальные символы после введенного char-а (вместе с '\n') останутся в потоке...

 ...
 cin >> d1 >> d2 >> c;
 cout << d1 << c << d2 << '\n';
 ....
avp@avp-xub11:~/hashcode$ ./a.out 
Enter op1 op2 cop: 22 333   
  +  
22+333
avp@avp-xub11:~/hashcode$
(23 Янв 17:14) avp

Казалось бы, простой вопрос..

(23 Янв 17:17) brightside90

@avp: а если вводить через Enter все три? Составить эксплоит не особо сложно, атакующий ведь контролирует адрес возврата. Первая же ссылка в гугле: http://www.insidepro.com/kk/011/011r.shtml

(23 Янв 17:24) VladD
1

@VladD, вот все три и даже с Enter-ом перед ними

avp@avp-xub11:~/hashcode$ ./a.out 
Enter op1 op2 cop:

11
12

*
11*12
avp@avp-xub11:~/hashcode$

без проблем.

--

По поводу переполнения буфера -- ну, понятно, я за надежное программирование. Тут самый простой вариант. В комментарии к ответу @brightside90, более правильный.

--

@brightside90,

Казалось бы, простой вопрос..

конечно, простой. Сложные тут так активно не обсуждают... (а жаль).

(23 Янв 17:33) avp

@avp: вот вам пример: http://ideone.com/m81g5R

(23 Янв 17:55) VladD
показано 5 из 10 показать еще 5
10|600 символов нужно символов осталось
3

Сделайте переменную с типа char и поменяйте ваш scanf("%d", &c); на scanf("%c", &c);

UPD: для корректной работы кода необходимо чистить поток ввода. Я больше ориентируюсь в С++, в С - меньше, но нужную вещь всегда можно нагуглить :)

fseek(stdin,0,SEEK_END);

Как я понял - это нужно добавить после первого и второго ввода, если я не прав, просветите, пожалуйста.

UPD2: странно, прогоняю код в 10 студии - всё работает. Прогоняю тут - не работает.

ссылка

отвечен 23 Янв 14:47

изменен 23 Янв 16:11

2

Чистить надо не всегда. Если scanf отработал нормально (вернул ожидаемое число, подробнее man scanf), то ничего чистить не надо.

А ввод данных у ТС, я бы изменил:

char inbuf[LINE_MAX];
printf("Enter two integer values and operation [+,-,/,*]: ");  fflush(stdout);
if (fgets(inbuf, sizeof(inbuf), stdin)) {
   int op1, op2, c, rc = sscanf(inbuf, "%d %d %s", &op1, &op2, inbuf);
   if (rc == 3) { 
     c = inbuf[0]; // теперь это будет первый не пробел после операндов !!!
     ...
   } else 
     puts("Invalid input);
  ......
(23 Янв 15:35) avp

@brightside90 только вот никакой код символа при scanf("%d", &c); не вводится.

(23 Янв 15:47) alexlz

@brightside90, а чего Вы удивляетесь (см. UPD2). Вы читаете в c следующий символ (прямо скажем байт) после второго операнда.

У Вас это '\n'. Для формата scanf("%c"...) все правильно. Если хотите пропустить пробелы между элементами ввода, то читайте "%s" (см. мой комментарий).

(23 Янв 16:01) avp

@alexlz согласен, с этим напорол

(23 Янв 16:03) brightside90

@VladD, там комментарии кончились.

Посмотрел на пример ideone.com. Вы хотели продемонстрировать, что С++ is ugly (RMS) или terrible (Linus) язык?

В принципе во многом с их оценкой крестов я согласен (по крайней мере с input/output) и сам предпочитаю чистый Си.

В коде на ideone проблема в смешивании cin >> (оставляет '\n' в потоке) с getline() (читает все до '\n').

Наверное тот формат правильно читать так -- число через cin >>, а потом в цикле getline(), пока не прочтем что-то не только из пробелов. Далее повторяем.

(23 Янв 18:15) avp

@avp: Скорее ugly. Смешивание всех возможных стилей ввода прекрасно работает в C#, C++ мог бы как-нибудь подружить свои собственные функции. Без getline обойтись нельзя, т. к. cin >> не умеет читать строки, содержащие пробелы.

(23 Янв 18:37) VladD

Проще всего вводить символ, как советует @brightside90, но непосредственно перед этим очистить входной поток

fflush(stdin);
scanf("%с", &c);

т.к. scanf оставляет символы в буфере. Переменная c может остаться типа int,

(23 Янв 18:52) paulgri
показано 5 из 7 показать еще 2
10|600 символов нужно символов осталось
0
#include <stdio.h>

int main(){
    int a, b;
    unsigned char c;
    printf("Enter 1 value:");
    scanf("%d", &a);

    printf("\nEnter 2 value:");
    scanf("%d", &b);

    while ( (c = getchar()) != '\n' && c != EOF ); //Очистка от мусора
    printf("\nEnter action you want to do with entered values[+,-,/,*]");
    c = getchar();

    printf("%c\n", c);

    switch(c) {
    case '+':
        printf("%d", a+b);
        break;
    case '-':
        printf("%d", a-b);
        break;
    case '*':
        printf("%d", a * b);
        break;
    case '/': 
        printf("%d", a/b);
        break;
    default:
        printf("\nEntered operator is not valid");
        return main();
    }

    system("PAUSE");
    return 0;
}
ссылка

отвечен 23 Янв 19:14

изменен 23 Янв 19:15

Просто и понятно. если scanf("%c",&c); "автозаполняется", значит нужно сделать так чтобы заполнилось только то что нам нужно. обычно остаются всякие '\n' поэтому добавляем

while ( (c = getchar()) != '\n' && c != EOF );

и всё это дело очищаем.

(23 Янв 19:18) Антон Лакотко

@Антон Лакотко, тогда уж getche и не надо printf после него

(23 Янв 19:48) paulgri
1

Действительно, если не зацикливаться на чтении всей тройки одним scanf(), то для чтения символа операции после того, как прочли оба операнда, вот такой код:

int c; // int это важно
...
while(isspace(c = getchar())); // пропустит лишние пробелы, ньюлайны и т.п.
switch (c) {
case EOF:
    .... // м.б. стоит обработать специально

IMHO выглядит вполне привлекательно

(24 Янв 0:24) avp
10|600 символов нужно символов осталось
Ваш ответ

Если вы не нашли ответ, задайте вопрос.

Здравствуйте

ХэшКод - это совместно редактируемый форум вопросов и ответов для начинающих и опытных программистов.

Присоединяйтесь!

отмечен:

×4,145
×1,209

задан
23 Янв 14:35

показан
394 раза

обновлен
24 Янв 0:24

Отслеживать вопрос

по почте:

Зарегистрировавшись, вы сможете подписаться на любые обновления

по RSS:

Ответы

Ответы и Комментарии

Железный партнер
Рейтинг@Mail.ru