Avatar
lukes90
Člen
Avatar
lukes90:

Ahoj,

jak ošetřím, aby nikdo nemohl zadat do proměnné int větší číslo, aby nepřeteklo.

Předem děkuji za odpověď.

 
Odpovědět 16. října 17:11
Avatar
ostrozan
Redaktor
Avatar
Odpovídá na lukes90
ostrozan:

úplně jednoduše - dej proměnné typ long, případně long long :-)

ale vážně - porovnej hodnotu s max hodnotou pro int - https://www.tutorialspoint.com/…limits_h.htm

 
Nahoru Odpovědět 16. října 17:55
Avatar
Odpovídá na ostrozan
Libor Šimo (libcosenior):

Predpokladam, ze nemyslis provnat to matematicky.

Nahoru Odpovědět 17. října 17:01
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
ostrozan
Redaktor
Avatar
ostrozan:

No původně jsem to tak myslel, ale teď si uvědomuju, že nevím jestli je dotaz na C, nebo C++.
Bude to podobné, ale C++ má asi víc nástrojů jak toho docílit.

 
Nahoru Odpovědět 17. října 21:53
Avatar
Odpovídá na ostrozan
Libor Šimo (libcosenior):

V céčku by bola optimálna funkcia, ktorá berie ako parameter reťazec a vracia int, ak spĺňa parametre int.

Nahoru Odpovědět 18. října 6:57
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
lukes90
Člen
Avatar
lukes90:

Byl to dotaz na c++. Omllouvám se za neuvedení. :-)

 
Nahoru Odpovědět 18. října 10:59
Avatar
Odpovídá na lukes90
Libor Šimo (libcosenior):

Otestuj.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <assert.h>
#define TESTY // pri zakomentovani budu testy odstavene

int parse_int(char *number)
{
    char *pom;

    pom = (char*)malloc(128);
    sprintf(pom, "%d", atoi(number));
    if (strcmp(number, pom)) {
        printf("Cislo nie je int!\n");
        return -1;
    }
    return atoi(number);
}

#ifdef TESTY
#define TESTY

int main(void)
{
    /** testy funkcie int parse_int(char *number) **/
    assert(parse_int("123456") == 123456);
    assert(parse_int("-123456") == -123456);
    assert(parse_int("2147483647") == INT_MAX);
    assert(parse_int("-2147483648") == INT_MIN);
    assert(parse_int("2147483657") == -1);
    assert(parse_int("2147483747") == -1);
    assert(parse_int("2147484647") == -1);
    assert(parse_int("2147493647") == -1);
    assert(parse_int("2147583647") == -1);
    assert(parse_int("2148483647") == -1);
    assert(parse_int("2157483647") == -1);
    assert(parse_int("2247483647") == -1);
    assert(parse_int("3147483647") == -1);
    assert(parse_int("2147483549") == 2147483549);
    assert(parse_int("2146499999") == 2146499999);
    assert(parse_int("2099999999") == 2099999999);
    assert(parse_int("2157483647265847589565888885445588555326598") == -1);

    printf("\n\nTesty presli.\n");

    return 0;
}

#endif // TESTY
Nahoru Odpovědět 18. října 13:11
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Martin Dráb
Redaktor
Avatar
Odpovídá na Libor Šimo (libcosenior)
Martin Dráb:

Tohle nebude fungovat, pokud chceš podporovat i čísla v jiné než desítkové soustavě, protože třeba 0x10 není řetězcově rovno 16. Plus tam alokuješ paměť, kterou neuvolňuješ. Vzhledem k tomu, kolik %d zabere max. znaků, ani alokace není třeba, stačí dostatečně velká lokální proměnná na zásobníku.

Nebylo by nejlepší použít třeba strtoll a náslecně porovnat s maximální/minimální hodnotou intu?

Nahoru Odpovědět 18. října 20:37
2 + 2 = 5 for extremely large values of 2
Avatar
DarkCoder
Člen
Avatar
Odpovídá na lukes90
DarkCoder:

Aby nikdo nemohl zadat do proměnné číslo tak aby nepřeteklo nezaručíš nikdy. Nepozorný programátor Ti ji naplní nesmyslnou hodnotou velmi snadno, třeba při inicializaci nebo přiřazení. Při překladu se mu zobrazí varovné hlášení, ale ne chybové. Viz. fragment kódu:

#include <limits.h>
#include <stdio.h>

...
int i = 1000000000000;
if((i>=INT_MIN)&&(i<=INT_MAX)) printf("%d", i);
else printf("i je mimo rozsah.\n");
...

Ikdyž je hodnota i evidentně mimo rozsah, hláška o tom, že tomu tak je, se nezobrazí.

Takže jakým způsobem, odkud se očekává hodnota proměnné typu int ze strany uživatele (ze souboru, z konzole, jako argument příkazového řádku, prostřednictvím síťové komunikace, atd)?

 
Nahoru Odpovědět 19. října 0:22
Avatar
ostrozan
Redaktor
Avatar
Odpovídá na lukes90
ostrozan:

Tady je několik různých řešení

 
Nahoru Odpovědět 19. října 5:07
Avatar
Odpovídá na Martin Dráb
Libor Šimo (libcosenior):

Nepredpokladal som, ze by chcel pouzit cisla ine ako desiatkovu sustavu a pre nu to funguje bezvadne. Ano mas pravdu v alokacii. Malo to byt staticky.

Nahoru Odpovědět 19. října 5:31
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Odpovídá na DarkCoder
Libor Šimo (libcosenior):

Ako som už písal vyššie, vstup musí byť string.

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>

using namespace std;

int parse_int(char *number)
{
    char pom[128];
    sprintf(pom, "%d", atoi(number));
    if (strcmp(number, pom)) {
        cout << "Cislo nie je int!" << endl;
        return -1;
    }
    return atoi(number);
}

int main(void)
{
    char cislo[] = "10000000000000000";
    parse_int(cislo);
    return 0;
}

Ale funguje to iba na typ int.
Myslím, že toto by mohla byť odpoveď na prvú otázku.

Nahoru Odpovědět 19. října 7:17
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Libor Šimo (libcosenior)
DarkCoder:

Přesněji řečeno vstupní data by měla být implementována a uložena do proměnné typu pole znaků. Předtím by však měla být otestována na paměťový rozsah a vyhodnocena na platnost, aby se nám do pole vešla. Zde už pracujeme s hotovou hodnotou. Řešení je to ale pěkné, neboť funkce atoi() dělá práci za nás. V případě přetečení rozsahu vrací hodnotu INT_MIN respektive INT_MAX což ve spojitosti s funkcí strcmp() dává požadovaný výsledek. Jedna věc tam ale není správná a to návratová hodnota funkce parse_int(). Nelze vracet hodnotu -1 v případě, že číslo není v daném rozsahu, neboť hodnota -1 koliduje s návratovou hodnotou získanou pomocí funkce atoi() v případě, že testovaným číslem je -1 a není tak zřejmé, jaká situace nastala.

 
Nahoru Odpovědět 19. října 15:43
Avatar
Martin Dráb
Redaktor
Avatar
Odpovídá na DarkCoder
Martin Dráb:

Nevím, zda by nebylo elegantnější zkusit strtol, která by měla v případě, že se zadaná hodnota do typu nevejde, nastavovat errno na ERANGE. Je tam ale třeba dávat pozor i na to, zda vůbec na vstupu číslo je, popř. zda nám stačí, pokud vstupní řetězec (resp. proměnná) číslem začíná, nebo zda musí obsahovat pouze číslo v řetězcové podobě. Chce to zkrátka pořádně přečíst dokumentaci a popřemýšlet.

Hm a to atoi-strcmp řešení stejně nebude fungovat pro řetězce ve stylu 00025.

Nahoru Odpovědět  +1 19. října 16:48
2 + 2 = 5 for extremely large values of 2
Avatar
Odpovídá na Martin Dráb
Libor Šimo (libcosenior):

Tie nuly ma nenapadly, ale staci mala uprava funkcie a bude to ok.

Nahoru Odpovědět 19. října 17:17
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Martin Dráb
Redaktor
Avatar
Odpovídá na Libor Šimo (libcosenior)
Martin Dráb:

Ano, stačí malá úprava. Ale už mi to začíná připadat jako takové flikování... :-).

Nahoru Odpovědět 19. října 17:22
2 + 2 = 5 for extremely large values of 2
Avatar
Odpovídá na DarkCoder
Libor Šimo (libcosenior):

Aj problem s -1 sa da jednoducho vyriesit. ;-)

Nahoru Odpovědět 19. října 17:23
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Nahoru Odpovědět 19. října 17:24
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Odpovídá na Martin Dráb
Libor Šimo (libcosenior):

Sorry, retazec -1 spracuje spravne a vrati cislo -1.

Nahoru Odpovědět 19. října 17:30
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Nahoru Odpovědět 19. října 17:32
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
ostrozan
Redaktor
Avatar
ostrozan:

a co třeba

int cisloInt;
long vstupni_data;

scanf("%[0-9]%li",&vstupni_data);
if(vstupni_data>INT_MAX)
{
////chyba
}
else cisloInt=vstupni_data;

a máš to i s ošetřením vstupu, aby bral jen numerické znaky

 
Nahoru Odpovědět 19. října 17:48
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Martin Dráb
DarkCoder:

Fragment kódu za použití funkce strtol()

unsigned int i = 0;
long int li;
char cislo[][15] = { "0", "-0", "+0", "100", "-100", "+100", "01000", "-01000", "+01000",
                              "2147483647", "-2147483648", "2147483648", "-2147483649", "" };

...
printf("%-16s%-16s%s\n\n", "Retezec", "Status", "Cislo");
while (strcmp(cislo[i], "")) {
        errno = 0;
        li = strtol(cislo[i], NULL, 10);
        if (errno==ERANGE) printf("%-16s%-16s%ld\n", cislo[i], "Mimo rozsah", li);
        else printf("%-16s%-16s%ld\n", cislo[i], "OK", li);
        i++;
}
...

I funkce atoi() resp. atol() nastavují při přetečení hodnotu makra errno na ERANGE. Výhodou funkce strtol() je ale možnost velmi snadno pracovat s konkrétní číselnou soustavou, možnost zastavit skenování a širší zpracování bílých znaků, jako třeba již zmíněné nuly. Použití funkce strtol() je tedy lepším řešením..

 
Nahoru Odpovědět  +1 20. října 3:43
Avatar
Odpovídá na DarkCoder
Libor Šimo (libcosenior):

Ešte vyriešiť napr. takýto string "2548R569", aby to vpísalo mimo rozsah a nie "2548R569" OK 2548.
Preklep sa užívateľovi priptrafí.

Nahoru Odpovědět 20. října 6:32
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Libor Šimo (libcosenior)
DarkCoder:
while (strcmp(cislo[i], "")) {
        errno = 0;
        if ((cislo[i][0] != '+') && (cislo[i][0] != '-') && (!isdigit(cislo[i][0]))) errno = ERANGE;
        else {
                for (j = 1; cislo[i][j]; j++) {
                        if (!isdigit(cislo[i][j])) {
                                errno = ERANGE;
                                break;
                        }
                }
                if (!errno) li = strtol(cislo[i], NULL, 10);
        }
        if (!errno) printf("%-16s%-16s%ld\n", cislo[i], "OK", li);
        else printf("%-16s%-16s\n", cislo[i], "Mimo rozsah");
        i++;
}

Doplněno o platné znaky na konkrétních pozicích znakového pole..

 
Nahoru Odpovědět  +1 20. října 9:25
Avatar
Martin Dráb
Redaktor
Avatar
Odpovídá na DarkCoder
Martin Dráb:

To bych spíš využil druhého parametru funkce strtol, abych nemusel provádět psí kusy a dělat v podstatě již to, co ta funkce tak jako tak provádí.

while (strcmp(cislo[i], "")) {
        char *endptr = cislo[i];
        errno = 0;
        li = strtol(cislo[i], &endptr, 10);
        if (*endptr != '\0')
            errno = ERANGE;

        if (errno==ERANGE) printf("%-16s%-16s%ld\n", cislo[i], "Mimo rozsah", li);
        else printf("%-16s%-16s%ld\n", cislo[i], "OK", li);
        i++;
}
Nahoru Odpovědět  +2 20. října 9:48
2 + 2 = 5 for extremely large values of 2
Avatar
Odpovídá na Martin Dráb
Libor Šimo (libcosenior):
li = strtol(cislo[i], &endptr, 10);
        if (*endptr != '\0')
            errno = ERANGE;

Správne som pochopil, že 10 znamená prevod na typ int a *endptr != '\0' znamená, že typ nie je int?

Nahoru Odpovědět 20. října 10:45
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Martin Dráb
Redaktor
Avatar
Odpovídá na Libor Šimo (libcosenior)
Martin Dráb:

10 znamená, že strtol bude akceptovat pouze řetězce zapisující čísla v desítkové soustavě. Podle mě je tato specifikace zbytečná. Obvykle dávám nulu (libovolná soustava, což efektivně znamená binární, osmičkovou, desítkovou či šestnáctkovou; záleží na prefixu čísla).

Argument endptr ti funkce naplní adresou znaku v řetězci, který se nachází hned za posledním znakem podřetězce zkonvertovaného na číslo. Takže když máš třeba řetězec 123R456, tak po jednom zavolání strtol bude endptr odkazovat na řetězec R456.

Pokud nechceš tyhle "částečné" konverze, tzn. pokud potřebuješ, aby se buď zkonvertoval celý řetězec, nebo nic, tak potřebuješ, aby po úspěšném zavolání strtol argument endptr odkazoval na konec řetězec, tedy na nulový znak.

Je ale pravda, že ta moje implementace může potlačit jiné chyby reportované fcí strtol (nebo je převede na ERANGE), což nemusí být to pravé ořechové.

Nahoru Odpovědět 20. října 11:03
2 + 2 = 5 for extremely large values of 2
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Martin Dráb
DarkCoder:

Ona i ta moje implementace přiřazovat makru errno hodnotu ERANGE u testu na platný znak asi nebude úplně správná. A tak zde přikládám kosmeticky upravenou implementaci testování.

while (strcmp(cislo[i], "")) {
        errno = 0;
        endptr = cislo[i];
        li = strtol(cislo[i], &endptr, 10);
        if ((*endptr != '\0') || (errno)) printf("%-16s%-16s\n", cislo[i], "Mimo rozsah");
        else printf("%-16s%-16s%ld\n", cislo[i], "OK", li);
        i++;
}
 
Nahoru Odpovědět 20. října 18:00
Avatar
ostrozan
Redaktor
Avatar
ostrozan:

Jak se na to tak dívám, už se dostáváte do oblastí, kde by se uplatnil spíš regex
Já ho teda používám všude, kde má vstup nějaký požadovaný formát (hlavně v C# aplikacích).

 
Nahoru Odpovědět 20. října 19:41
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 29 zpráv z 29.