2D pole - dynamicka alokace a uvolneni rubrika: Programování: C/C++

4 Levin
položil/-a 21.11.2015
 
upravil/-a 22.11.2015

Ahoj, hledam zpusob jak si alokovat 2d pole podle vstupu od uzivatele, napr. 4 4. Z toho vytvorit pol o 4 radcich. a 4 sloupcich. Nasel jsem zpusob to resit pres *array
tim vyresit 1. Radek a zbyle radky resit for cyklem, kde
array. Existuje nejaky jiny zpusob bez cyklu?

Druha otazka je ohledne uvolneni, jak uvolnim z pameti pote to pole, je nutne na to zase pouzit cyklus?

Edit: nejdou mi vlozit 2 hvezdicky vedle sebe, u toho prvniho array maji byt dve a u toho druheho jedna
Edit2: Jde o jazyk C, ne C++

Komentáře

  • nixbody : A je nutne, aby to pole bylo dvourozmerne, nestacilo by udelat jednorozmerne o velikosti sirka * vyska a k polozkam pristupovat takto: matrix[sirka * y + x]? 22.11.2015
odkaz Vyřešeno
4 nov.ondrej
odpověděl/-a 22.11.2015

V čistém C neexistuje pole. Tím bych asi začal. Zápis prom[x] znamená *(prom+x), kde prom je ukazatel někam do paměti a x je offset. C ještě navíc ctí typ, takže si umí x vynásobit délkou typu. To je celé.

Dvojrozměnné pole lze realizovat dvěma způsoby. První je, že x spočítám jako I*cols + J, kde I je řádek, cols je počet sloupců a J je sloupec.

Abych takové pole zkonstruoval, stačí mi spočítat počet prvků v poli, pomocí vzorce cols*rows.

int *pole2D   = (int *) calloc( cols*rows, sizeof(int))

Přístup do pole pak jako

int a = pole2D[ i * cols + j ]
pole2D[ i * cols + j ] = b

Tady je vidět, že potřebujete si s polem pamatovat cols

Dealokace pole je jednoduchá,

free(pole2D)

Druhý způsob je vytvořit pole polí. Pak první pole obsahuje ukazatele na další pole.

int **pole2D = (int **) calloc(rows, sizeof (int *))
for (i = 0; i < rows; i++) pole2D[i] = (int *)calloc(cols,sizeof(int));

Přístup do pole:

int a = pole2D[i][j]
pole2D[i][j] = b

Výhodou je, že si nemusím pamatova žádné cols

Dealokace pole je složitější, je třeba zničit všechny řádky

for (i = 0; i < rows; i++) free(pole2D[i]);
free(pole2D);

Je vidět, že pro dealokaci je třeba znát rows. To se někdy dá obejít tím, že v některých platformách mohu zjistit velikost alokováného bloku (_msize() ve Windows), ale tohle považuju trochu za prasečinu. Lepší řešení by bylo pole uložit jako strukturu

typedef struct Pole2D {
    int rows, cols;
    int **data;
} POLE2D;

a napsat funkce, které s takovou strukturou pracuji.

Přístup do takového POLE2D x by byl

x.data[i][j]

Co se týče náročnosti na CPU a paměť, tak první způsob je jednoznačně rychlejší a zabírá méně paměti, ale nemusí být hned intuitivní. Druhý způsob vyžaduje extra inicializaci a extra uvolnění a kromě alokace paměti pro prvky vyžaduje alokaci tabulky pointerů pro řádky. Ale třeba umožňuje hybridní pole, kdy každá řádká má jiný počet prvků.

Omlouvám se za syntaxtické chyby, píšu to z hlavy narychlo.

Komentáře

  • nixbody : Vase odpoved je dobra, ale bylo vazne nutne psat, ze C nema pole? To pak muzu rict, ze nema ani promenne, protoze to je vlastne jen syntactic sugar pro pointery nekam do stacku. 22.11.2015
  • nov.ondrej : @Nobody: Problém je ten, že spousta lidí si pole představuje podobně jako jsou realizovaná pole v jiném jazyce, kde pole bývají opravdu pole. Stejně tak C nemá ani string, ale pouze ukazatel na znak a string z toho dělají jen knihovní funkce. Tohle je obrovská past pro začínající programátory, kteří se v tom rychle ztratí a mohou pak zanevřít na celý programovací jazyk. Pamatuju si sebe, jak jsem nadával na C, že je to šílený jazyk. V té době jsem programoval v Turbo Pascalu. Pak jsem v C naprogramoval _známou_ hru a nyní programuju v C++ 22.11.2015
  • nixbody : @nov.ondrej: No, ja jsem to mel presne naopak, kdyz jsem nekdy v 7. tride prechazel z Turbo Pascalu na C, tak jsem byl nadseny, jak je tam vse jednoduche a naprosto jasne :) Navic Turbo/Borland C umoznovalo udelat pointer primo do videopameti, coz bylo mnohem pohodlnejsi, nez v Pascalu, kde jsem to psal v inline ASM. Omlouvam se za OT, dychla na me nostalgie :) 22.11.2015
  • Kit : Spíš bych napsal, že C má pole, ale většina moderních jazyků ho nemá. 22.11.2015
  • nov.ondrej : Ještě bych k tomu přidal lehce "hackerský" způsob, kdy provedu int **pole2D = (int **)malloc(rows*sizeof(int *)+rows*cols*sizeof(int)). Vznikne mi prostor pro tabulku pointerů a vlastní data. Tabulku pointerů musím inicializovat cyklem, ale hodnotu těch pointerů už spočítám jako pole2D+rows*sizeof(int *)+i*cols*sizeof(int), kde i je číslo řádku, jehož pointer během inicializace počítám. Pak se to chová jako pole polí. Zjednoduší mi to dealokaci, kdy stačí udělat jen free na celé pole2D. Myšlenka je jednoduchá, alokovaný prostor prostě rozdělí oblast na pole řádku a datovou oblast, kde jsou pak realizované jednotlivé řádky. Jeden čas jsem podobný princip v C používal na stringtables, kdy se to tvářilo jako pole stringů, vlastní string byly uloženy za polem ... pole obsahovalo pointery ukazující právě do této oblasti. Dodnes to používám třeba u sdílení stringtables mezi procesy, často místo pointerů jsou tam uloženy offsety, protože se paměť sdílí mezi procesy přičemž v každém procesu na jiné base adrese. 22.11.2015
  • Tomáš Tintěra : Pozor že C ani C++ pole nejde normálně předat jako parametr do funkce viz https://www.safaribooksonline.com/library/view/c-primer-fifth/9780133053... . A také je potřeba upozornit, že v C++ už je doporučeno místo Cčkového pole používat vector. Takže je to lepší brát, že C a C++ pole nemá. 23.11.2015
  • Kit : To už je fakt lepší ten Fortran, hlavně pohodlnější. O sedmidimenzionálním poli si C/C++ mohou nechat jen zdát. 23.11.2015
  • Tomáš Tintěra : <offtopic>Ukázka fungování pole v C++ , Gist </offtopic> 23.11.2015
  • Hape : The C programming language, Kerningham, Ritchie, kapitola 5, "Pointers and Arrays" 27.11.2015

Pro zobrazení všech 3 odpovědí se prosím přihlaste:

Rychlé přihlášení přes sociální sítě:

Nebo se přihlaste jménem a heslem:

Zadejte prosím svou e-mailovou adresu.
Zadejte své heslo.