Načtení 2D pole v C

Re:Načtení 2D pole v C
« Odpověď #15 kdy: 20. 11. 2022, 17:40:42 »
Otázka zní, zda vůbec používat funkci scanf() a zda by nebylo lepší udělat si vlastní konečný automat a načítat si ta čísla po znacích. Je to dost triviální.

To by teda nebylo lepší :) Je to dost citlivá funkce, protože načítá vstup, udělat to správně a bez chyb není vůbec triviální. A to se bavíme jen o integerech, floaty jsou úplně jiná liga. A navíc je to úplně mimo mísu pro začátečníka...

Ano, bavíme se o integerech. Jaké hrozné problémy tam jsou? V čem je lepší používat obskurní funkce typu scanf()?.

Tak napriklad
  • znamenka
  • "inty" nejsou jen int, ale i char, unsigned char, signed char, short... mel byste checkovat rozsahy (scanf hlasi nekompatibilni formatovaci string a typ uz pri prekladu)
  • scanf umi i hex a oct - pokud uloha tazatele "pocita" se scanf, musi se pocitat se vsim, co scanf umi
  • musite spravne preskakovat whitespace znaky
  • musite vubec definovat, jak se funkce bude chovat v chybovych a krajnich pripadech, napr. pro retezec "123ab" scanf nacte cislo "123" a zbytek necha na vstupu - jak se bude chovat vase funkce?
  • musite spravne osetrit buffer overflow - to je asi nejtezsi

A vubec, vse vyse zminene je naprosto nepodstatne, protoze zvolit "napsat si to sam" i kdyz je k dispozici standardni funkce je vzdy spatna volba (pokud nepotrebujete vyzdimat kazdou mikrosekundu) - a to z mnoha duvodu: kazdy, kdo to vezme po vas, si tu funkci bude muset precist, protoze nevi, co dela, pokud najde chybu, vy budete kopat okolo, ze "jste to tak myslel" - namisto "aha, scanf, ok, ten znam...".

To, co jsem napsal plati pro produkcni kod, ale dost hrubym zpusobem to miji pointu tohoto vlakna. Tazatel je zacatecnik, chce nacist matici, dostal zadani udelat to v C a scanf je v tom jazyce standardni funkce...


Ink

  • *****
  • 668
    • Zobrazit profil
    • E-mail
Re:Načtení 2D pole v C
« Odpověď #16 kdy: 20. 11. 2022, 19:34:08 »
A vubec, vse vyse zminene je naprosto nepodstatne, protoze zvolit "napsat si to sam" i kdyz je k dispozici standardni funkce je vzdy spatna volba (pokud nepotrebujete vyzdimat kazdou mikrosekundu) - a to z mnoha duvodu: kazdy, kdo to vezme po vas, si tu funkci bude muset precist, protoze nevi, co dela, pokud najde chybu, vy budete kopat okolo, ze "jste to tak myslel" - namisto "aha, scanf, ok, ten znam...".

Kdybych to měl řešit "po svém", pravděpodobně bych nepoužil C, kdybych musel použít C, je otázka, zda bych měl k dispozici jenom tyhle "standardní" funkce apod.

To, co jsem napsal plati pro produkcni kod, ale dost hrubym zpusobem to miji pointu tohoto vlakna. Tazatel je zacatecnik, chce nacist matici, dostal zadani udelat to v C a scanf je v tom jazyce standardni funkce...

OK, v pohodě. Zadání jsem neviděl - buďto tu není nebo jsem ho přehlédl. Přesto mi nepřijde to řešení s konečným automatem v takovémto případě špatné - vyřeší celkem jednoduše řádkování atd. Znaménko, whitespace apod. jsou úplně v pohodě, ošetřit "správně" invalidní znak je triviální, poskládání integeru z dekadického zápisu je triviální. Řešit hexa číslo je zvláštní, že se int nevejde do mezí typu je sice možné, ale co na tom vyřeší scanf()? Co když někdo napíše do vstupu stočíslicovou hodnotu?

Re:Načtení 2D pole v C
« Odpověď #17 kdy: 20. 11. 2022, 21:22:12 »
Tahle debata nema vyznam :) Ano, to, co pisete je jeden ze zpusobu, jak parsovat cela cisla ze stringu.

Nicmene:

1. Tazatel neumi nacist pole ze vstupu, kde berete jistotu, ze zvladne spravne naprogramovat stavovy automat?
2. I pokud se bavime o produkcnim kodu, znovu,  scanf je standardni funkce. Pointa "standardnich" funkcionalit nespociva primarne v tom, ze jsou krasne (i kdyz zrovna scanf je vcelku ok - clovek si holt musi precist dokumentaci), ale v tom, ze to pouziva ranec existujicich aplikaci, vsichni to znaji, vsichni vedi, ze to funguje spravne a nikdo nepotrebuje studovat kod.
3. Tohle je C-specific vlakno, neni to C++, neni to Ruby, neni to Java. A holt v C je scanf (amd friends) standard. Nema cenu zde psat, co si myslite o C, ja si o Jave, Ruby... taky myslim sve.

Predpokladam, ze kdyz stavite dum, take netezite holyma rukama jil a nepalite vlastni cihly.

alex6bbc

  • *****
  • 1 639
    • Zobrazit profil
    • E-mail
Re:Načtení 2D pole v C
« Odpověď #18 kdy: 20. 11. 2022, 21:28:48 »
Predpokladam, ze kdyz stavite dum, take netezite holyma rukama jil a nepalite vlastni cihly.

kdyz chce nekdo proniknout do veci, tak si i ty cihly muze sam udelat a vyzkouset si to.
pak kdyz zjisti jak to funguje, nasledne muze prejit na cihly co uz jsou k dispozici.

Re:Načtení 2D pole v C
« Odpověď #19 kdy: 20. 11. 2022, 22:14:04 »
Používám tuto konstrukci, čte celý řádek a pak řádek parsuje daným separátorem.

char *separator = " \t";
FILE *file = fopen( "jmeno_souboru.txt", "rt" );

fscanf( file, "%[^\n]s", line ); fgetc( file );

int index = atoi( strtok( line, separator ) );
double koef = atof( strtok( NULL, separator ) );


Re:Načtení 2D pole v C
« Odpověď #20 kdy: 20. 11. 2022, 23:11:15 »
Predpokladam, ze kdyz stavite dum, take netezite holyma rukama jil a nepalite vlastni cihly.

kdyz chce nekdo proniknout do veci, tak si i ty cihly muze sam udelat a vyzkouset si to.
pak kdyz zjisti jak to funguje, nasledne muze prejit na cihly co uz jsou k dispozici.

Lenze totalny zaciatocnik ktory ma problem nacitat 2d maticu nepotrebuje vediet ako funguje scanf interne, a uz toboz sa nepotrebuje pokusat napodobnit jeho functionalitu vlastnou implementaciou.

Ked si niekto robi vodicak, tiez ho instruktor nevezme do oceliarni aby videl ako sa odlieva ocel, z ktorych sa nasledne robia diely, a neprejdu si spolu celu vyrobnu linku v automobilke. Co ale urobi je to, ze ho uci ako pouzivat to co uz je k dispozicii (hotove auto). Ked clovek naberie dost skusenosti zo soferovanim moze sa zacat hrabat v motore. Nie je to dokonaly priklad, ale na pochopenie hadam staci.
« Poslední změna: 20. 11. 2022, 23:12:50 od kanoe22 »

BoneFlute

  • *****
  • 1 983
    • Zobrazit profil
Re:Načtení 2D pole v C
« Odpověď #21 kdy: 20. 11. 2022, 23:24:16 »
kdyz chce nekdo proniknout do veci, tak si i ty cihly muze sam udelat a vyzkouset si to.
pak kdyz zjisti jak to funguje, nasledne muze prejit na cihly co uz jsou k dispozici.

Na youtubu jsem viděl pár videí několika lidí, kteří to skutečně tak udělali. V reálném životě neznám nikoho. Tedy vulgo: ano, máte pravdu, ale ta vaše pravda je k ničemu.

Ink

  • *****
  • 668
    • Zobrazit profil
    • E-mail
Re:Načtení 2D pole v C
« Odpověď #22 kdy: 21. 11. 2022, 06:58:40 »
Používám tuto konstrukci, čte celý řádek a pak řádek parsuje daným separátorem.

char *separator = " \t";
FILE *file = fopen( "jmeno_souboru.txt", "rt" );

fscanf( file, "%[^\n]s", line ); fgetc( file );

int index = atoi( strtok( line, separator ) );
double koef = atof( strtok( NULL, separator ) );

Tokenizace + zpracování po řádcích? To vypadá jako plán.

Ink

  • *****
  • 668
    • Zobrazit profil
    • E-mail
Re:Načtení 2D pole v C
« Odpověď #23 kdy: 21. 11. 2022, 07:01:11 »
kdyz chce nekdo proniknout do veci, tak si i ty cihly muze sam udelat a vyzkouset si to.
pak kdyz zjisti jak to funguje, nasledne muze prejit na cihly co uz jsou k dispozici.

Na youtubu jsem viděl pár videí několika lidí, kteří to skutečně tak udělali. V reálném životě neznám nikoho. Tedy vulgo: ano, máte pravdu, ale ta vaše pravda je k ničemu.

A co jiného je výuka C, než základní pochopení, jak program funguje na mikroúrovni?

alex6bbc

  • *****
  • 1 639
    • Zobrazit profil
    • E-mail
Re:Načtení 2D pole v C
« Odpověď #24 kdy: 21. 11. 2022, 09:01:35 »
jeste by slo pouzit mmap.

mikrom

  • ****
  • 367
    • Zobrazit profil
    • E-mail
Re:Načtení 2D pole v C
« Odpověď #25 kdy: 21. 11. 2022, 16:45:28 »
Zatial je tu mnoho filozofickej diskusie, ale malo kodu, tak postnem ja - ako som uz vyssie spomenul, da sa to vyriesit so standardnymi C funkciami fgets() a strtok() napr. takto:

matrix.c
Kód: [Vybrat]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_ROWS 100
#define MAX_COLS 100
#define MAX_LINE_LENGTH 256

int main()
{
    FILE *fp;
    char matrix_line[MAX_LINE_LENGTH];
    char *matrix_element;
    int i, j, max_i, max_j;
    int num_element;
    int matrix[MAX_ROWS][MAX_COLS];

    fp = fopen("matrix.dat","r");

    printf("Reading data from the file into the matrix:\n");
    i = 0;
    while (fgets(matrix_line, MAX_LINE_LENGTH, fp) != NULL) {
        // split line into matrix elements
        matrix_element = strtok(matrix_line, ",;\t ");
        j = 0;
        while(matrix_element != NULL) {
            // populate matrix
            matrix[i][j] = atoi(matrix_element);
            j++;
            matrix_element = strtok(NULL, ",;\t ");
        }
        i++;
    }
    max_i = i;
    max_j = j;
    fclose(fp);
    printf("..DONE.\n\n");

    // now print the matrix
    printf("The matrix is:\n");
    for (i = 0; i < max_i; i++) {
        for (j = 0; j < max_j; j++) {
            printf("%d\t", matrix[i][j]);
        }
        printf("\n");
    }

    return 0;
}

Nacita zo suboru matica.dat takuto
Kód: [Vybrat]
1 2 3 4
5 6 7 8
alebo aj takuto maticu kde su prvky oddelene roznymi separatormi.
Kód: [Vybrat]
1; 2, 3 4
5 6; 7 8

Output:
Kód: [Vybrat]
$ gcc matrix.c -o matrix

$ matrix
Reading data from the file into the matrix:
..DONE.

The matrix is:
1       2       3       4
5       6       7       8

Re:Načtení 2D pole v C
« Odpověď #26 kdy: 21. 11. 2022, 17:56:04 »
Zatial je tu mnoho filozofickej diskusie, ale malo kodu, tak postnem ja - ako som uz vyssie spomenul, da sa to vyriesit so standardnymi C funkciami fgets() a strtok() napr. takto:

matrix.c
Kód: [Vybrat]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_ROWS 100
#define MAX_COLS 100
#define MAX_LINE_LENGTH 256

int main()
{
    FILE *fp;
    char matrix_line[MAX_LINE_LENGTH];
    char *matrix_element;
    int i, j, max_i, max_j;
    int num_element;
    int matrix[MAX_ROWS][MAX_COLS];

    fp = fopen("matrix.dat","r");

    printf("Reading data from the file into the matrix:\n");
    i = 0;
    while (fgets(matrix_line, MAX_LINE_LENGTH, fp) != NULL) {
        // split line into matrix elements
        matrix_element = strtok(matrix_line, ",;\t ");
        j = 0;
        while(matrix_element != NULL) {
            // populate matrix
            matrix[i][j] = atoi(matrix_element);
            j++;
            matrix_element = strtok(NULL, ",;\t ");
        }
        i++;
    }
    max_i = i;
    max_j = j;
    fclose(fp);
    printf("..DONE.\n\n");

    // now print the matrix
    printf("The matrix is:\n");
    for (i = 0; i < max_i; i++) {
        for (j = 0; j < max_j; j++) {
            printf("%d\t", matrix[i][j]);
        }
        printf("\n");
    }

    return 0;
}

No... stačí tam poslat více jak MAX_ROWS řádků a máme ukázkový buffer overflow na stacku s (remote) code execution.  CVSS score 10/10 ;).

mikrom

  • ****
  • 367
    • Zobrazit profil
    • E-mail
Re:Načtení 2D pole v C
« Odpověď #27 kdy: 21. 11. 2022, 19:00:19 »
No... stačí tam poslat více jak MAX_ROWS řádků a máme ukázkový buffer overflow na stacku s (remote) code execution.  CVSS score 10/10 ;).
To neni produkcny kod ale iba ukazka JAK NA TO.
Vyhnut sa problemu o ktorom hovoris sa da roznymi sposobmi - napriklad:
- Osetrit podmienkou aby sa do matice nacitalo len tolko riadkov kolko riadkov ma subor.
- Najprv nacitat subor 1. krat, pritom zistit pocet riadkov (pripadne aj stlpcov), nasledne alokovat maticu danej velkosti, potom urobit rewind a nacitat subor 2. krat  do matice.

Re:Načtení 2D pole v C
« Odpověď #28 kdy: 21. 11. 2022, 19:12:00 »
To neni produkcny kod ale iba ukazka JAK NA TO.

To je spíš ukázka, JAK TO NEDĚLAT. Problémů je tam víc.

Nestačí ošetřit počet řádků, další buffer overflow nastane, když bude v řádku víc jak MAX_COLS (100) prvků. To jde snadno docílit, protože MAX_LINE_LENGTH je 256, jde tam nacpat až 128 prvků. Výsledek je úplně stejný, přepis stacku s (remote) code execution.

Pak je tam uninitialized memory access v případě, když budou mít řádky různý počet sloupců, matrix není inicializované. Neinicializovaná data se potom vypisují a může tam být cokoliv, třeba šifrovací klíče, které program používá.

Tohle bych začátečníkovi fakt neukazoval.

mikrom

  • ****
  • 367
    • Zobrazit profil
    • E-mail
Re:Načtení 2D pole v C
« Odpověď #29 kdy: 21. 11. 2022, 19:30:42 »
To neni produkcny kod ale iba ukazka JAK NA TO.

To je spíš ukázka, JAK TO NEDĚLAT.
...
Toto su malicherne nedostatky, ktore sa daju lahko osetrit. Rozne ucebnice a navody su plne takychto prikladov. Cielom je aby bol priklad kratky a lahko zrozumitelny a to aj je.
Keby si mal nejaku sebareflexiu, tak by si namiesto kritiky radsej postol vlastny funkcny kod, co sa ale nestalo.