Стандартная библиотека С имеет для ввода с консоли функцию scanf. Эта функция очень плохо контролирует правильность ввода, и нормальные программисты настоятельно не рекомендуют её использовать, даже в простых программах. Так что пытаемся сделать аналог. Функции должны компилироваться(и работать начиная от 5150) начиная от TurboC 1.0 или 3.0 точно так что используем С89. Спойлер Код (C): /* Функции замены scanf Blackspace - стереть крайний символ Esc - стереть строку полностью Enter - ввести данные (c) Intro 8.05.2022 */ #include <stdio.h> #include <string.h> #include <conio.h> #ifndef bool #define bool char #define true 1 #define false 0 #endif int InputInt() { int N; /* кол. введёных символов */ char buf[15], buf2[15]; bool negative = false; /* фл. отрицательного числа */ int res = 0; for (N=0;;){ int S = getch(); if (S==13 && N>(negative ? 1 : 0)) break; /* Enter */ if (S=='-' && N==0 && !negative){ /* минус */ negative = true; buf[N++] = S; buf[N] = 0; putchar(S); }else if (S>='0' && S<='9'){ /* Цифры */ int digit = (S-'0'); int tmp = res*10 + (negative ? -digit : digit); if (N==(negative ? 2 : 1) && buf[N-1]=='0'){ /* убираем лишние нули */ --N; cputs("\b \b"); } /* Ввод символа */ buf[N++] = S; buf[N] = 0; /* символ и терм. нуль */ sprintf(buf2, "%d", tmp); /* проверка переполнения */ if (strcmp(buf, buf2)!=0){ buf[--N] = 0; putchar('\a'); /* гудок */ continue; } res = tmp; putchar(S); }else if (S==27 || S==8){ /* Esc и Blackspace */ while (N>0){ if (negative && N==1) negative = false; else res /= 10; buf[--N] = 0; cputs("\b \b"); if (S==8) break; /* Blackspace */ } } } return res; } unsigned int InputUInt() { int N; /* кол. введёных символов */ char buf[15], buf2[15]; unsigned int res = 0; for (N=0;;){ int S = getch(); if (S==13 && N>0) break; /* Enter */ if (S>='0' && S<='9'){ /* Цифры */ unsigned int tmp = res*10+(S-'0'); if (N==1 && buf[0]=='0'){ /* убираем лишние нули */ --N; cputs("\b \b"); } /* Ввод символа */ buf[N++] = S; buf[N] = 0; /* символ и терм. нуль */ sprintf(buf2, "%u", tmp); /* проверка переполнения */ if (strcmp(buf, buf2)!=0){ buf[--N] = 0; putchar('\a'); /* гудок */ continue; } res = tmp; putchar(S); }else if (S==27 || S==8){ /* Esc и Забой */ while (N>0){ res /= 10; buf[--N] = 0; cputs("\b \b"); if (S==8) break; /* Забой */ } } } return res; } Пока нету для float и строк. Потом.
Проверять целое число на переполнение путем форматирования его в строку и сравнения строк, нормальные программисты тоже настоятельно не рекомендуют. Разве что это для govnokod.ru библиотека ввода, тогда не страшно --- Сообщение объединено, 8 май 2022 --- Intro, И кстати, если ты хочешь, чтобы компилилось любым компилем, то объявлять переменные можно только в начале функции до первого оператора и присваивать значение можно только после объявления переменной. То, что твой код компилится - это просто у мс такой c89, с блекджеком и шл.хами Код (C): int main () { int i, result; result = 0; /* int result = 0 - нельзя */ for (i=0; ...) /* for (int i=0; ...) - нельзя */ { /* int j; внутри цикла нельзя */ /* однострочных комментариев в бородатом си тоже нет, кстати :) */ } return result; }
Не придумал ничего лучшего, кроме того хотел получить код для шаблонов С++. Не понятно чего просто tmp>MAX_INT где tmp это long long int не работает, не работает и всё. Ассемблер рулит, там это работает. Это просто костыли, но они работают, а значит это нормальный код. По идеи должно быть так. Код (C++): try { tmp = res*10 + (negative ? -digit : digit); } catch (integer_overflow) { buf[--N] = 0; putchar('\a'); /* гудок */ continue; } Но это С++, и я не знаю можно ли отследить переполнение таким образом. Технически это очень легко можно сделать на любых, абсолютно любых системах, т.к. carry есть везде.
Intro, Я же тебе в другом топике показал, как отслеживать переполнения ДО того, как оно произойдет. Добавление разряда к целому - value = value * 10 + digit. Максимальное значение для uint32 - 4294967295. Таким образом, если текущее значение value меньше 429496729, можно спокойно добавлять следующий разряд, переполнения гарантированно не будет. Если текущее значение равно 429496729, то добавить без переполнения можно только разряд со значением 0..5. Если же текущее значение больше 429496729, то никакой разряд добавить нельзя, переполнение будет гарантированно. Код (C): static bool AppendDigit (uint32* value, int digit/* 0..9 */, bool isSigned) { if (isSigned) { if (value > 429496729 || (value == 429496729 && digit > 5)) return FALSE; } else if (value > 214748364 || (value == 214748364 && digit > 7)) return FALSE; *value = *value * 10 + digit; return TRUE; } uint32 ReadInt (bool* isSigned/* out */) { uint32 value; int c, sign, length; value = 0; length = 0; sign = 0; while (TRUE) { c = GetChar(); if (IsDigit (c)) { if (!AppendDigit (&value, c - '0', sign == '-')) { // overflow } else { length++; PutChar (c); } } else if (c == '-' || c == '+') { if (sign != 0 || length != 0) { // invalid character } else { sign = c; length++; PutChar (c); } } else if (c == '\b') { if (length != 0) { PutChar (c); value /= 10; length--; } } else if (c == 27) { while (length--) PutChar ('\b'); value = 0; sign = 0; length = 0; } else if (c == '\n') { if (length != 0) break; } else { // invalid character } } if (sign == '-') { *isSigned = TRUE; value = ~value + 1; } else *isSigned = FALSE; return value; }
Ага смог победить компиляхтор, возьми с полки пирожок. Но мой код хорошо натягивается на шаблоны С++, разных типов целых от байта до __m128 или __m256 Быстродействие? Ну тут это совершенно не актуально, даже для 8088, там в getch основное время ожидание.
Предлагаю для полноты треша и угара printf'ить не само число, а все выражение целиком, потом evaluate'ить vbs'ом, перенаправлять выхлоп в файл и читать из него результат. Кампуцеры нонча мощные, не треснут.
Да я понял, я дурак! if (res>MAX_UINT/10 || (res== MAX_UINT/10 &&res> MAX_UINT %10)) Просто надо было выпить водочки стакан. Точней даже 250 мл И это код так же ложиться на шаблоны С++. --- Сообщение объединено, 11 май 2022 --- Точней так Код (C): /* проверка переполнения */ if (res>UINT_MAX/10 || (res==UINT_MAX/10 && (S-'0')>UINT_MAX%10)){
Обновил код, но прежний мне больше нравиться. Все, ну почти все, ну многие современные погромисты так пишут, причём даже в отвественных местах. И даже получают тыщи деняг Код (C): /* Функции замены scanf ver 0.01 Blackspace - стереть крайний символ Esc - стереть строку полностью Enter - ввести данные (c) Intro 8.05.2022 14.05.2022 */ #include <stdio.h> //#include <string.h> #include <conio.h> #include <limits.h> #ifndef bool #define bool char #define true 1 #define false 0 #endif int InputInt() { int res, N; /* кол. введёных символов */ char buf[15]; bool negative = false; /* фл. отрицательного числа */ for (N=0, res=0;;){ int S = getch(); if (S==13 && N>(negative ? 1 : 0)) break; /* Enter */ if (S=='-' && N==0 && !negative){ /* минус */ negative = true; buf[N++] = S; buf[N] = 0; putchar(S); }else if (S>='0' && S<='9'){ /* Цифры */ int digit; if (N==(negative ? 2 : 1) && buf[N-1]=='0'){ /* убираем лишние нули */ --N; cputs("\b \b"); } digit = negative ? -(S-'0') : (S-'0'); /* проверка переполнения */ if (negative && (res<INT_MIN/10 || (res==INT_MIN/10 && digit<INT_MIN%10)) || (res>INT_MAX/10 || (res==INT_MAX/10 && digit>INT_MAX%10))){ putchar('\a'); /* гудок */ continue; } /* Ввод символа */ buf[N++] = S; buf[N] = 0; /* символ и терм. нуль */ res = res*10 + digit; putchar(S); }else if (S==27 || S==8){ /* Esc и Blackspace */ while (N>0){ if (negative && N==1) negative = false; else res /= 10; buf[--N] = 0; cputs("\b \b"); if (S==8) break; /* Blackspace */ } } } return res; } unsigned int InputUInt() { int N; /* кол. введёных символов */ char buf[15]; unsigned int res; for (N=0, res=0;;){ int S = getch(); if (S==13 && N>0) break; /* Enter */ if (S>='0' && S<='9'){ /* Цифры */ int digit; if (N==1 && buf[0]=='0'){ /* убираем лишние нули */ --N; cputs("\b \b"); } digit = S-'0'; /* проверка переполнения */ if (res>UINT_MAX/10 || (res==UINT_MAX/10 && digit>UINT_MAX%10)){ putchar('\a'); /* гудок */ continue; } /* Ввод символа */ res = res*10+digit; buf[N++] = S; buf[N] = 0; /* символ и терм. нуль */ putchar(S); }else if (S==27 || S==8){ /* Esc и Забой */ while (N>0){ res /= 10; buf[--N] = 0; cputs("\b \b"); if (S==8) break; /* Забой */ } } } return res; }
Код (C): /* Функции замены scanf ver 0.02 Blackspace - стереть крайний символ Esc - стереть строку полностью Enter - ввести данные (c) Intro 8.05.2022 18.05.2022 */ #include <stdio.h> #include <conio.h> #include <limits.h> int InputInt() { int res, N; /* кол. введёных символов */ int negative; /* фл. отрицательного числа */ for (N=0, res=0, negative=0;;){ int S = getch(); if (S==13 && N>negative) break; /* Enter */ if (S=='-' && N==0 && !negative){ /* минус */ negative = 1; N++; putchar(S); }else if (S>='0' && S<='9'){ /* Цифры */ int digit; if (N==(negative+1) && res==0){ /* убираем лишние нули */ --N; cputs("\b \b"); } digit = S-'0'; if (negative) digit = -digit; /* проверка переполнения */ if (negative && (res<INT_MIN/10 || res==INT_MIN/10 && digit<INT_MIN%10) || (res>INT_MAX/10 || res==INT_MAX/10 && digit>INT_MAX%10)){ putchar('\a'); /* гудок */ continue; } /* Ввод символа */ res = res*10 + digit; ++N; putchar(S); }else if (S==27 || S==8){ /* Esc и Blackspace */ while (N>0){ if (negative && N==1) negative = 0; else res /= 10; --N; cputs("\b \b"); if (S==8) break; /* Blackspace */ } } } return res; } unsigned int InputUInt() { int N; /* кол. введёных символов */ unsigned int res; for (N=0, res=0;;){ int S = getch(); if (S==13 && N>0) break; /* Enter */ if (S>='0' && S<='9'){ /* Цифры */ int digit; if (N==1 && res==0){ /* убираем лишние нули */ --N; cputs("\b \b"); } digit = S-'0'; /* проверка переполнения */ if (res>UINT_MAX/10 || (res==UINT_MAX/10 && digit>UINT_MAX%10)){ putchar('\a'); /* гудок */ continue; } /* Ввод символа */ res = res*10+digit; ++N; putchar(S); }else if (S==27 || S==8){ /* Esc и Blackspace */ while (N>0){ res /= 10; --N; cputs("\b \b"); if (S==8) break; /* Blackspace */ } } } return res; } Так уже лучше, ничего лишнего.