Išgalvotas būdas atskirti dvimatį matricą?

Projekte kažkas paspaudė šią eilutę:

 double (*e)[n+1] = malloc((n+1) * sizeof(*e)); 

Tai, kas turėtų sukurti dvimatį masyvą (n + 1) * (n + 1), padvigubinama.

Manau, nes iki šiol niekas, kuriam aš paprašiau, galėčiau man tiksliai pasakyti, ką jis daro ir kur jis atėjo, arba kodėl jis turėtų veikti (tariamai tai atsitinka, bet aš to dar neperkau).

Galbūt aš neturiu nieko akivaizdaus, bet norėčiau tai vertinti, jei kas nors galėtų man paaiškinti virš linijos. Nes aš asmeniškai jaučiuosi daug geriau, jei naudoju tai, ką iš tiesų suprantame.

108
22 апр. User1291 nustatytas 22 Bal 2016-04-22 15:43 '16 at 15:43 2016-04-22 15:43
@ 3 atsakymai

Kintamasis e yra double tipo n + 1 elementų masyvo rodyklė.

Naudojant dereference operatorių e , gausite e tipo bazinį tipą, kuris yra „ double tipo n + 1 elementų masyvas“.

Skambinant „ malloc paprasčiausiai malloc e tipo tipas (paaiškintas aukščiau) ir gaunamas jo dydis, padauginamas iš n + 1 ir perduodamas toks dydis iki malloc funkcijos. Iš esmės n + 1 double elementų masyvo paskirstymas.

86
22 апр. atsakymą pateikė „ Some programmer dude“ balandžio 22 d 2016-04-22 15:51 '16 at 15:51 PM 2016-04-22 15:51

Tai yra tipiškas būdas dinamiškai paskirstyti dvimatę matricą.

  • e yra masyvo rodyklė double [n+1] tipo double [n+1] masyvui.
  • Todėl dydis sizeof(*e) nurodo smailės tipo tipą, kurio dydis yra vienas double [n+1] masyvas double [n+1] .
  • Jūs skiriate vietos n+1 tokioms matricoms.
  • Jūs nurodėte masyvo rodyklę e į masyvo matricos pirmąją matricą.
  • Tai leidžia naudoti e kaip e[i][j] kad galėtumėte pasiekti atskirus 2D masyvo elementus.

Asmeniškai manau, kad šis stilius yra daug lengviau skaitomas:

 double (*e)[n+1] = malloc( sizeof(double[n+1][n+1]) ); 
55
22 апр. atsakymą pateikė Lundin balandžio 22 d 2016-04-22 15:51 '16 at 15:51 PM 2016-04-22 15:51

Ši idioma natūraliai išeina iš 1D masyvo pasiskirstymo. Pradedame išgauti 1D masyvą tam tikro tipo T :

 T *p = malloc( sizeof *p * N ); 

Paprasta, ar ne? Išraiška *p yra T tipo, todėl sizeof *p suteikia tą patį rezultatą kaip sizeof (T) , todėl skiriame pakankamai vietos N elementų T masyvui. Tai pasakytina apie bet kurį T tipą.

Dabar pakeiskime T R [10] tipo tipu R [10] . Tada mūsų pasiskirstymas tampa

 R (*p)[10] = malloc( sizeof *p * N); 

Semantika čia yra lygiai tokia pati kaip 1D paskirstymo metodas; visa, kas pasikeitė, yra p . Vietoj T * dabar T * R (*)[10] . Sąvoka *p turi T tipą, kuris yra R [10] tipas, todėl sizeof *p lygus sizeof (T) , kuris yra lygus sizeof (R [10]) . Todėl skiriame pakankamai vietos N 10 R elementų R

Mes galime tai padaryti dar labiau, jei norime; Tarkime, kad R pats yra masyvo tipas int [5] . Pavadinkite R ir gaukite

 int (*p)[10][5] = malloc( sizeof *p * N); 

Tas pats dalykas - sizeof *p sutampa su sizeof (int [10][5]) , ir mes užbaigiame nepertraukiamo atminties kiekio, kuris yra pakankamai didelis, kad galėtume turėti N nuo 10 iki 5 int .

Taigi į paskirstymo pusę; ką apie prieigos pusę?

Atminkite, kad indekso operacija [] yra apibrėžta pagal rodyklės aritmetiką: a[i] yra apibrėžiama kaip *(a + i) 1 . Taigi indekso operatorius [] netiesiogiai atkuria rodyklę. Jei p yra rodyklė į T , nurodytą vertę galite pasiekti naudodamiesi vienareikšmišku naudojimu naudojant vieningą operatorių * :

 T x = *p; 

arba naudojant indekso operatorių [] :

 T x = p[0]; // identical to *p 

Taigi, jei p nurodo pirmąjį masyvo elementą, galite pasiekti bet kurį šio masyvo elementą, naudodami rodyklės rodyklę p :

 T arr[N]; T *p = arr; // expression arr "decays" from type T [N] to T * ... T x = p[i]; // access the i'th element of arr through pointer p 

Dabar dar kartą atlikite pakeitimo operaciją ir pakeiskite T su R [10] tipo tipu R [10] :

 R arr[N][10]; R (*p)[10] = arr; // expression arr "decays" from type R [N][10] to R (*)[10] ... R x = (*p)[i]; 

Vienas akivaizdus skirtumas; mes, žinoma, grojame p prieš pradedant indekso operatorių. Mes nenorime indeksuoti į p , mes norime indeksuoti į tai, ką p nurodo (šiuo atveju masyvas arr[0] ). Kadangi vieningas * turi mažesnį prioritetą nei [] indeksas, mes turime naudoti skliaustelius aiškiai grupei p su * . Tačiau atminkite, kad *p sutampa su p[0] , todėl galime jį pakeisti

 R x = (p[0])[i]; 

ar tiesiog

 R x = p[0][i]; 

Taigi, jei p nurodo 2D masyvą, mes galime indeksuoti šį masyvą per p :

 R x = p[i][j]; // access the i'th element of arr through pointer p; // each arr[i] is a 10-element array of R 

Atsižvelgiant į tą pačią išvadą kaip ir anksčiau, ir pakeičiant R į int [5] :

 int arr[N][10][5]; int (*p)[10][5]; // expression arr "decays" from type int [N][5][10] to int (*)[10][5] ... int x = p[i][j][k]; 

Tai veikia lygiai taip pat, jei p nurodo įprastą matricą arba nurodo per malloc priskirtą atmintį.

Šis idiomas turi šiuos privalumus:

  • Tai paprasta - tik viena eilutė kodo, o ne atrankos metodas
     T **arr = malloc( sizeof *arr * N ); if ( arr ) { for ( size_t i = 0; i < N; i++ ) { arr[i] = malloc( sizeof *arr[i] * M ); } } 
  • Visos pasirinktos matricos eilutės yra * gretimos *, kuri netaikoma aukščiau aprašytam skaidymo metodui;
  • Masyvo free yra toks pat paprastas, kai skambinate vienu metu. Vėlgi, tai yra neteisinga, kai pasirinksite palaipsniui pasirinktą metodą, kur jūs turite paleisti kiekvieną arr[i] kad galėtumėte paleisti arr .

Kartais pageidaujamas žingsnis po žingsnio metodas, pavyzdžiui, kai jūsų krūva yra labai susiskaidžiusi ir negalite priskirti savo atminties kaip nuolatinio fragmento, arba norite priskirti „nelygią“ masyvą, kur kiekviena eilutė gali būti skirtingo ilgio, tačiau apskritai tai yra geriausias būdas eiti. .


1. Atminkite, kad matricos nėra rodyklės, o masyvo išraiškos konvertuojamos į rodyklių išraiškas, kai reikia.
39
22 апр. Atsakymą pateikė John Bode balandžio 22 d 2016-04-22 19:33 '16 at 19:33 2016-04-22 19:33

Peržiūrėkite kitus klausimus apie žymes, arba „ Užduoti klausimą“