2D-dynaamisen taulukon luominen kohdassa c. 2D dynaaminen matriisi

Yleensä tietyn muuttujan vaatima muistin määrä asetetaan ennen käännösprosessia ilmoittamalla tämä muuttuja. Jos on tarvetta luoda muuttuja, jonka kokoa ei tiedetä etukäteen, käytetään dynaamista muistia. Varaus Ja vapauttaa Muistihäviö C++-ohjelmissa voi tapahtua milloin tahansa. Toiminta käynnissä jakelu muisti kahdella tavalla:

  • funktiota käyttämällä malloc, calloc, realloc Ja vapaa;
  • operaattorin kautta Uusi Ja poistaa.

Toiminto malloc varauksia vierekkäinen varastosolujen lohko määritetty objekti ja palauttaa osoittimen tämän lohkon ensimmäiseen soluun. Funktion kutsu näyttää tältä:

void *malloc(koko);

Tässä koko- etumerkitön kokonaislukuarvo, joka määrittää varatun muistialueen koon tavuina. Jos muistin varaus onnistui, toiminto palaa tyyppinen muuttuja tyhjä *, joka voidaan vähentää mihin tahansa vaadittu tyyppi osoitin.

Toiminto - calloc käytetään myös muistin varaamiseen. Alla oleva merkintä tarkoittaa, että se korostetaan nro elementtejä koko tavu.

void *calloc(nime, koko);

Tämä funktio palauttaa osoittimen valintaan tai TYHJÄ kun muistia ei ole mahdollista varata. Toiminnon ominaisuus on kaikkien valittujen elementtien nollaus.

Toiminto reallocmuuttaa kokoa aiemmin varattu muisti. He puhuttelevat häntä näin:

char *realloc (tyhjä *p, koko);

Tässä s- osoitin muistialueelle, jonka kokoa muutetaan koko. Jos muistialueen osoite muuttuu funktion toiminnan seurauksena, niin uusi osoite palaa sen seurauksena. Jos todellinen arvo ensimmäinen parametri TYHJÄ, sitten toiminto realloc toimii samalla tavalla kuin toiminto malloc, eli se varaa osan muistista, jonka koko on koko tavu.

Vapauta varattu muisti käyttämällä toimintoa vapaa. He puhuttelevat häntä näin:

void free (tyhjä *p koko);

Tässä s- osoitin muistialueelle, jonka funktiot ovat aiemmin osoittaneet malloc, calloc tai realloc.

Operaattorit Uusi Ja poistaa vastaavia toimintoja malloc Ja vapaa. Uusi varaa muistia, ja sen ainoa argumentti on lauseke, joka määrittää varattavien tavujen määrän. Palauttaa operaattoriosoittimen varatun muistilohkon alkuun. Operaattori poistaa vapauttaa muistia, sen argumentti on vapautettavan lohkon ensimmäisen solun osoite.

dynaaminen matriisi- joukko vaihteleva pituus, jonka muisti on varattu ohjelman suorittamisen aikana. Muistin varaaminen tapahtuu funktioiden mukaan calloc, malloc tai operaattori Uusi. Varatun muistin ensimmäisen elementin osoite on tallennettu muuttujaan, joka on ilmoitettu osoittimena. Esimerkiksi seuraava lause tarkoittaa, että osoitin on ilmoitettu mas ja määritti vierekkäisen alueen alun osoitteen dynaaminen muisti, valittu operaattorilla Uusi:

int *mas=uusi int;

Muistia on varattu niin paljon kuin tarvitaan 10 int-arvon tallentamiseen.

Itse asiassa muuttujassa mas tallennettu osoite nolla elementti dynaaminen matriisi. Siksi seuraavan, ensimmäisen elementin osoite allokoidulla muistialueella on mas+1 ja mas+i on i:nnen elementin osoite. Pääsy dynaamisen taulukon i:nteen elementtiin voidaan tehdä tavalliseen tapaan mas[i] tai muulla tavalla *(mas+i) . On tärkeää varmistaa, että et ylitä varatun muistialueen rajoja.

Kun dynaaminen matriisi(milloin tahansa ohjelma on käynnissä) ei enää ole tarpeen, niin muistia voidaan vapauttaa toiminnolla vapaa tai operaattori poistaa.

Ehdotan harkitsemaan useita tehtäviä, jotka vahvistavat tätä oppituntia:

Tehtävä 1

Etsi dynaamisen taulukon todellisten elementtien summa.

//Käyttöesimerkki malloc-toiminnot ja ilmainen #include "stdafx.h" #include käyttäen nimiavaruutta std; int main() ( setlocale(LC_ALL,"Rus"); int i, n; float *a; //osoitin kelluttamaan s; cout<<"\n"; cin>>n; //taulukon dimension syöttö //muistin varaaminen n reaalielementin joukolle a=(float *)malloc(n*sizeof(float)); cout<<"Введите массив A \n"; //ввод элементов массива for (i=0; i>*(a+i); ) //taulukon elementtien summan kerääminen kohteelle (s=0, i=0; i

//Esimerkki malloc- ja free-funktioiden käytöstä

#include "stdafx.h"

#sisältää

käyttäen nimiavaruutta std ;

int main()

int i, n;

kellua * a ; //osoitin kellumaan

kellua s ;

cout<< "\n" ; cin >>n; //syötä taulukon ulottuvuus

//muistin varaaminen n reaalielementin joukolle

a = (kelluke * ) malloc (n * koko (float ) ) ;

cout<< "Syötä matriisi A \n";

//syötä taulukon elementit

for (i = 0; i< n ; i ++ )

cin >> * (a + i );

//taulukon elementtien summan kertyminen

for (s = 0, i = 0; i< n ; i ++ )

s+=* (a+i);

//summan lähtöarvo

cout<< "S=" << s << "\n" ;

// vapaa muisti

ilmainen(a);

system("tauko");

paluu 0;

Tehtävä 2

Muokkaa dynaamista kokonaislukujonoa niin, että sen positiiviset elementit muuttuvat negatiivisiksi ja päinvastoin. Ongelman ratkaisemiseksi kerromme jokaisen elementin -1:llä.

//Esimerkki uusien ja delete-operaattoreiden käytöstä #include "stdafx.h" #include käyttäen nimiavaruutta std; int main() ( setlocale(LC_ALL,"Rus"); int i, n; //syötä cout-taulukon elementtien lukumäärä<<"n="; cin>>n; //muistin varaus int *a=uusi int[n]; cout<<"Введите элементы массива:\n"; //ввод массива for (i=0; i>a[i]; //annetun taulukon tulos (i=0; i

//Esimerkki uusien ja delete-operaattoreiden käytöstä

#include "stdafx.h"

#sisältää

käyttäen nimiavaruutta std ;

int main()

setlocale(LC_ALL , "Rus" );

int i, n;

//syötä taulukon elementtien lukumäärä

cout<< "n=" ; cin >>n;

//muistin varaus

int * a = uusi int [ n ] ;

cout<< "Anna taulukon elementit:\n";

//taulukon syöttö

Keräessäni tietoja tämän artikkelin kirjoittamista varten muistin ensimmäisen tutustumiseni osoittimiin - siellä oli surua ... Siksi luettuani useita tätä aihetta käsitteleviä osia useista C ++ -ohjelmointia koskevista kirjoista päätettiin mennä eri tavalla ja esitellä aihe C ++ -osoittimista siinä järjestyksessä, jossa pidän sitä tarpeellisena. Annan sinulle heti lyhyen määritelmän ja tarkastelemme työssä viitteitä - esimerkein. Seuraava artikkeli () käsittelee vivahteita, osoittimien käyttöä C-tyylisten merkkijonojen (merkkijonojen) kanssa ja tärkeimmät muistettavat asiat.

Osoitin C++:ssa on muuttuja, joka tallentaa tietojen (arvojen) osoitteen muistiin, ei itse dataa.

Tarkastellessaan seuraavia esimerkkejä, ymmärrät pääasia - miksi tarvitsemme ohjelmointiohjeita, kuinka niitä julistaa ja käyttää.

Oletetaan, että meidän täytyy luoda ohjelmassa kokonaislukutaulukko, jonka tarkkaa kokoa emme tiedä ennen ohjelman käynnistymistä. Eli emme tiedä kuinka monta numeroa käyttäjän on lisättävä tähän taulukkoon. Tietysti voimme pelata varman päälle ja ilmoittaa useiden tuhansien elementtien joukon (esimerkiksi 5 000). Tämän (subjektiivisen mielipiteemme) pitäisi riittää, jotta käyttäjä toimii. Kyllä – todellakin – se saattaa riittää. Mutta älkäämme unohtako, että tämä ryhmä vie paljon tilaa RAM-muistista (5 000 * 4 (kirjoita int) = 20 000 tavua). Sitten varmistimme, että käyttäjä täyttää vain 10 elementtiä taulukostamme. Osoittautuu, että 40 tavua on todella toiminnassa, ja 19 960 tavua vie muistia turhaan.

RAM-muistin kohtuuton käyttö

#sisältää käyttäen nimiavaruutta std; int main() ( setlocale(LC_ALL, "rus"); const int SizeOfArray = 5000; int arrDigits = (); cout<< "Массив занял в памяти " << sizeof(arrWithDigits) << " байт" << endl; int amount = 0; cout << "Сколько чисел вы введёте в массив? "; cin >> määrä; cout<< "Реально необходимо " << amount * sizeof(int) << " байт" << endl; for (int i = 0; i < amount; i++) { cout << i + 1 << "-е число: "; cin >> arrNumeroilla[i]; ) leikata<< endl; for (int i = 0; i < amount; i++) { cout << arrWithDigits[i] << " "; } cout << endl; return 0; }

#sisältää

käyttäen nimiavaruutta std ;

int main()

const int SizeOfArray = 5000 ;

int arrNummerilla [SizeOfArray] = ();

cout<< "Matriisi varattu muistiin"<< sizeof (arrWithDigits ) << " байт" << endl ;

int määrä = 0 ;

cout<< "Kuinka monta numeroa laitat taulukkoon?";

cin >> määrä ;

cout<< "Todella tarpeellinen"<< amount * sizeof (int ) << " байт" << endl ;

for (int i = 0 ; i< amount ; i ++ )

cout<< i + 1 << "-е число: " ;

cin >> arrNumeroilla[ i ] ;

cout<< endl ;

for (int i = 0 ; i< amount ; i ++ )

cout<< arrWithDigits [ i ] << " " ;

cout<< endl ;

paluu 0;

Tavalliseen kirjastotoimintoon koko() ilmoitetun taulukon ohittaminen arrNumeroilla rivi 10. Se palauttaa puhelusivustolle sen koon tavuina, jonka tämä joukko varaa muistissa. Kysymykseen "Kuinka monta numeroa syötät taulukkoon?" vastaus - 10. Rivillä 15 lauseke määrä * koko(int) tulee yhtä suureksi kuin 10 * 4, koska funktio koko (int) palauttaa 4 (koko tavuina tyyppiä int). Syötä seuraavaksi numerot näppäimistöltä ja ohjelma näyttää ne näytöllä. Osoittautuu, että loput 4990 elementtiä tallentavat nollia. Joten on turha näyttää niitä.

Päätiedot näytöllä: taulukko vei 20 000 tavua, mutta todellisuudessa se tarvitsee 40 tavua. Kuinka päästä eroon tästä tilanteesta? Ehkä joku haluaa kirjoittaa ohjelman uudelleen niin, että käyttäjä syöttää taulukon koon näppäimistöltä ja arvon syöttämisen jälkeen ilmoittaa taulukon, jossa on tarvittava määrä elementtejä. Mutta tämä ei onnistu ilman viitteitä. Kuten muistat, taulukon koon on oltava vakio. Toisin sanoen kokonaislukuvakio on alustettava ennen taulukon ilmoitusta, emmekä voi pyytää sen syöttöä näppäimistöltä. Kokeile - tarkista.


Tässä operaattori on korostanut meidät punaisella >> koska et voi muuttaa vakioarvoa.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


Tässä meitä varoitetaan, että taulukon koko EI voi olla tavallisen muuttujan arvo. Vakioarvo vaaditaan!

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Seuraavassa koodissa käytämme sinulle uusia osoitinta ja operaattoreita. Uusi(varaa muistia) ja poistaa(vapauttaa muistia).

järkevä käyttö RAM-muistia käyttämällä osoittimia

#sisältää #sisältää käyttäen nimiavaruutta std; int main() ( setlocale(LC_ALL, "rus"); int sizeOfArray = 0; // taulukon koko (käyttäjän syöte) cout<< "Чтобы создать массив чисел, введите его размер: "; cin >>sizeOfArray; // HUOMIO! int* arrWithDigits - ilmaisee osoittimen // muistiin, jonka uusi int* varaa arrWithDigits = uusi int ; for (int i = 0; i< sizeOfArray; i++) { arrWithDigits[i] = i + 1; cout << arrWithDigits[i] << " "; } cout << endl; delete arrWithDigits; // освобождение памяти return 0; }

#sisältää

#sisältää

käyttäen nimiavaruutta std ;

int main()

setlocale(LC_ALL , "rus" ) ;

int sizeOfArray = 0; // taulukon koko (käyttäjän syöte)

cout<< "Luo numerosarja antamalla sen koko: ";

cin >> sizeOfArray ;

// HUOMIO! int* arrWithDigits - osoittimen ilmoitus

// muistialueelle, jonka uusi varaa

int * arrWithDigits = uusi int [ sizeOfArray ] ;

for (int i = 0 ; i< sizeOfArray ; i ++ )

arrNumeroilla[ i ] = i + 1 ;

cout<< arrWithDigits [ i ] << " " ;

cout<< endl ;

poista arrWithDigits ; // vapauttaa muisti

paluu 0;

Käyttäjä syöttää arvon näppäimistöltä - riviltä 12. Osoitin määritellään alla: int * arrNumeroilla Tämä merkintä tarkoittaa sitä arrNumeroilla on osoitin. Se luotiin tallentamaan sen solun osoite, jossa kokonaisluku sijaitsee. Meidän tapauksessamme arrNumeroilla osoittaa taulukon soluun, jonka indeksi on 0. Merkki * - sama kuin kertolaskussa käytetty. Kontekstista kääntäjä "ymmärtää", että tämä on osoittimen ilmoitus, ei kertolasku. Seuraavaksi tulee merkki = ja operaattori Uusi, joka varaa muistialueen. Muistamme, että muistimme tulee varata taulukolle, ei yhdelle numerolle. Äänite uusi int[sizeOfArray] voidaan purkaa näin: Uusi(varaa muistia) int(kokonaislukujen tallentamiseen) (Määrässä sizeOfArray ).

Siten rivillä 16 määriteltiin dynaaminen matriisi. Tämä tarkoittaa, että sen muisti varataan (tai ei varata) ohjelman toiminnan aikana, ei kääntämisen aikana, kuten tavallisten taulukoiden tapauksessa. Toisin sanoen muistin varaaminen riippuu ohjelman kehityksestä ja päätöksistä, jotka tehdään suoraan sen työssä. Meidän tapauksessamme se riippuu siitä, mitä käyttäjä syöttää muuttujaan sizeOfArray

Rivi 25 käyttää lausetta poistaa. Se vapauttaa varatun operaattorin Uusi muisti. Koska Uusi varattu muisti taulukon varaamista varten, sitten kun se vapautetaan, on välttämätöntä tehdä kääntäjälle selväksi, että on tarpeen vapauttaa taulukon muisti, ei vain sen nollasolu, mikä osoittaa arrNumeroilla. Siksi välillä poistaa ja osoittimen nimi on suljettu hakasulkeissa poista arrWithDigits ; On muistettava, että joka kerta kun muistia varataan käyttämällä Uusi, sinun on vapautettava tämä muisti käyttämällä poistaa. Tietenkin ohjelman lopussa sen käyttämä muisti vapautetaan automaattisesti. Mutta ota hyvä tapa käyttää operaattoreita Uusi Ja poistaa pariksi. Loppujen lopuksi ohjelma voi sisältää esimerkiksi 5-6 taulukkoa. Ja jos vapautat muistia joka kerta, kun sitä ei enää tarvita käynnissä olevassa ohjelmassa, muistia käytetään älykkäämmin.

Oletetaan, että ohjelmassamme täytimme matriisin kymmenellä arvolla. Sitten he laskivat summansa ja kirjoittivat sen johonkin muuttujaan. Ja siinä kaikki – emme enää työskentele tämän taulukon kanssa. Ohjelma jatkaa toimintaansa ja siihen luodaan uusia dynaamisia taulukoita joihinkin tarkoituksiin. Tässä tapauksessa on suositeltavaa vapauttaa ensimmäisen taulukon käyttämä muisti. Sitten kun varaat muistia muille taulukoille, tätä muistia voidaan käyttää uudelleen ohjelmassa.

Harkitse osoittimien käyttöä funktioparametreina. Aloita kirjoittamalla ja kääntämällä seuraava koodi. Siinä funktio vastaanottaa kaksi muuttujaa ja tarjoaa muutoksia niiden arvoihin.

yrittää muuttaa funktioon välitettyjä muuttujia

#sisältää #sisältää käyttäen nimiavaruutta std; void changeData(int varForCh1, int varForCh2); int main() ( setlocale(LC_ALL, "rus"); int muuttujaForChange_1 = 0; int muuttujaForChange_2 = 0; cout<< "variableForChange_1 = " << variableForChange_1 << endl; cout << "variableForChange_2 = " << variableForChange_2 << endl; cout << endl; changeData(variableForChange_1, variableForChange_2); cout << endl; cout << "variableForChange_1 = " << variableForChange_1 << endl; cout << "variableForChange_2 = " << variableForChange_2 << endl; return 0; } void changeData(int varForCh1, int varForCh2) { cout << "Введите новое значение первой переменной: "; cin >>varForCh1; cout<< "Введите новое значение второй переменной: "; cin >> varForCh2; )

#sisältää

#sisältää

käyttäen nimiavaruutta std ;

void changeData (int varForCh1 , int varForCh2 );

int main()

setlocale(LC_ALL , "rus" ) ;

int variableForChange_1 = 0 ;

int variableForChange_2 = 0 ;

cout<< "variableForChange_1 = " << variableForChange_1 << endl ;

cout<< "variableForChange_2 = " << variableForChange_2 << endl ;

cout<< endl ;

changeData (muuttujaForChange_1 , variableForChange_2 ) ;

cout<< endl ;

cout<< "variableForChange_1 = " << variableForChange_1 << endl ;

cout<< "variableForChange_2 = " << variableForChange_2 << endl ;

paluu 0;

void changeData(int varForCh1 , int varForCh2 )

cout<< "Anna uusi arvo ensimmäiselle muuttujalle:";

cin >> varForCh1 ;

cout<< "Anna uusi arvo toiselle muuttujalle:";

cin >> varForCh2 ;

Suorita ohjelma ja syötä uudet muuttujan arvot. Lopulta näet, että funktion lopussa muuttujat eivät ole muuttuneet ja ovat yhtä kuin 0.

Kuten muistat, funktio ei toimi suoraan muuttujien kanssa, vaan luo niistä tarkat kopiot. Nämä kopiot tuhoutuvat toiminnon sulkemisen jälkeen. Toisin sanoen funktio sai jonkin muuttujan parametriksi, loi siitä kopion, työskenteli sen kanssa ja tuhosi sen. Itse muuttuja pysyy ennallaan.

Osoittimien avulla voimme välittää muuttujaosoitteita funktiolle. Tällöin funktio pystyy toimimaan suoraan osoitettujen muuttujien kanssa. Tehdään muutoksia edelliseen ohjelmaan.

muuttujien arvojen muuttaminen osoittimien avulla

#sisältää #sisältää käyttäen nimiavaruutta std; void changeData(int* varForCh1, int* varForCh2); int main() ( setlocale(LC_ALL, "rus"); int muuttujaForChange_1 = 0; int muuttujaForChange_2 = 0; cout<< "variableForChange_1 = " << variableForChange_1 << endl; cout << "variableForChange_2 = " << variableForChange_2 << endl; cout << endl; changeData(&variableForChange_1, &variableForChange_2); cout << endl; cout << "variableForChange_1 = " << variableForChange_1 << endl; cout << "variableForChange_2 = " << variableForChange_2 << endl; return 0; } void changeData(int* varForCh1, int* varForCh2) { cout << "Введите новое значение первой переменной: "; cin >> *varForCh1; cout<< "Введите новое значение второй переменной: "; cin >> *varForCh2; )

Luennon tarkoitus: tutkia yksiulotteisten dynaamisten taulukoiden ilmoituksia, muistin varaamista ja vapauttamista, pääsyä elementteihin, oppia ratkaisemaan ongelmia käyttämällä yksiulotteisia dynaamisia taulukoita C ++ -kielellä.

Useita tietorakenteita käytettäessä riittää usein, että niiden koko on vaihteleva aikana läpimenoaika ohjelmia. Näissä tapauksissa on tarpeen hakea dynaaminen muistin varaus. Yksi yleisimmistä tällaisista tietorakenteista ovat taulukot, joissa kokoa ei aluksi ole määritelty eikä kiinteä.

Mukaan kielistandardi taulukko on kokoelma elementtejä, joilla jokaisella on samat attribuutit. Kaikki nämä elementit sijoitetaan vierekkäisille muistialueille rivissä alkaen taulukon alkua vastaavasta osoitteesta. Toisin sanoen matriisielementtien kokonaismäärä ja sille varatun muistin koko saadaan täysin ja yksiselitteisesti taulukon määritelmän mukaan. Mutta tämä ei ole aina kätevää. Joskus vaaditaan, että taulukolle varattu muisti on mitoitettu tietyn ongelman ratkaisemiseksi, ja sen määrää ei tiedetä etukäteen eikä sitä voida korjata. Vaihtelevan kokoisten taulukoiden (dynaamisten taulukoiden) muodostaminen voidaan järjestää osoittimien ja työkalujen avulla dynaaminen muistin varaus.

dynaaminen matriisi on taulukko, jonka kokoa ei ole vahvistettu etukäteen ja joka voi muuttua ohjelman suorituksen aikana. Kokoa muuttamaan dynaaminen matriisi ohjelmointikieli C++, joka tukee tällaisia ​​taulukoita, tarjoaa erityistä sisäänrakennetut toiminnot tai operaatioita. Dynaamiset taulukot mahdollistavat joustavamman työskentelyn datan kanssa, koska niiden avulla ei voida ennustaa tallennettuja tietomääriä, vaan säätää taulukon kokoa todellisuudessa tarvittavien volyymien mukaan.

Yksiulotteisten dynaamisten taulukoiden ilmoittaminen

Yksiulotteisen julistuksen mukaan dynaaminen matriisi ymmärtää osoittimen määrittely tietyn tyyppiselle muuttujalle, jotta tätä muuttujaa voidaan käyttää dynaaminen matriisi.

Syntaksi :

Kirjoita * ArrayName;

Tyyppi - ilmoitettujen elementtien tyyppi dynaaminen matriisi. Elementit dynaaminen matriisi eivät voi olla funktioita ja elementtejä tyhjä tyyppi.

Esimerkiksi:

int*a; kaksinkertainen *d;

Näissä esimerkeissä a ja d ovat osoittimia varatun muistialueen alkuun. Osoittimet ottavat allokoidun muistialueen osoitteen arvoille, jotka ovat tyyppiä int ja tyyppi double.

Näin ollen, kun varaat dynaamisesti muistia dynaamisille taulukoille, sinun tulee kuvata vastaava osoitin , jolle annetaan varatun muistialueen alun osoitteen arvo.

Muistin varaus yksiulotteiselle dynaamiselle taulukolle

Muistin varaamiseksi yksiulotteiselle dynaaminen matriisi C++-kielessä on kaksi tapaa.

1) leikkauksen avulla new , joka varaa sopivan kokoisen osan dynaamisesta muistista taulukon mukaiseksi, eikä salli taulukon elementtien alustamista.

Syntaksi :

ArrayName = uusi tyyppi [ConstantTypeExpression];

ArrayName - taulukon tunniste, eli varatun muistilohkon osoittimen nimi.

ExpressionTypeConstants– asettaa elementtien määrän ( taulukon dimensio).. Vakiotyyppinen lauseke arvioidaan käännöshetkellä.

Esimerkiksi:

int *mas; mas = uusi int ; /* dynaaminen muistivaraus 100*(int) tavun koko*/ double *m = uusi tupla [n]; /*varaa n*koko (kaksi) tavua dynaamisesta muistista*/ pitkä (*lm); lm = uusi pitkä ; /*varaa 2*4*(pitkien) tavujen kokoa dynaamista muistia*/

Dynaamista muistia varattaessa on taulukon mitat oltava täysin määriteltyjä.

2) käyttämällä kirjastotoimintoa malloc (calloc) , jota käytetään dynaamisen muistin varaamiseen.

Syntaksi :

ArrayName = (Tyyppi *) malloc(N*koko(tyyppi));

ArrayName = (Tyyppi *) calloc(N, sizeof(Type));

ArrayName - taulukon tunniste, eli varatun muistilohkon osoittimen nimi.

Tyyppi on taulukon osoittimen tyyppi.

N on taulukon elementtien lukumäärä.

Esimerkiksi:

kellua *a; a=(kelluke *)malloc(10*(kelluke)); // tai a=(float *)calloc(10,sizeof(float)); /*10 dynaamisen muistin koon allokointi*(float) tavun koko*/

Koska malloc(calloc)-funktio palauttaa kirjoittamaton osoitin void * , sinun on muunnettava tuloksena oleva

// 10 elementin kaksiulotteisen dynaamisen taulukon ilmoitus:

float **ptrarray = uusi float* ; // kaksi merkkijonoa taulukossa

for (int count = 0; count< 2; count++)

ptrarray = uusi float ; // ja viisi saraketta

// jossa ptrarray on joukko osoittimia allokoidulle muistialueelle float-tyyppisten reaalilukujen joukolle

Ensin ilmoitetaan float **ptrarray toisen asteen osoitin, joka viittaa float* osoittimien joukkoon, jossa taulukon koko on kaksi . Tämän jälkeen for-silmukassa taulukon jokainen rivi on ilmoitettu in linja 2 muistia on varattu viidelle elementille. Tuloksena saadaan kaksiulotteinen dynaaminen matriisi ptrarray. Tarkastellaan esimerkkiä kaksiulotteiselle dynaamiselle taulukolle varatun muistin vapauttamisesta.

// kaksiulotteiselle dynaamiselle taulukolle varatun muistin vapauttaminen:

for (int count = 0; count< 2; count++)

poista ptraray;

// jossa 2 on rivien lukumäärä taulukossa

#sisältää
#sisältää
#sisältää
void main()
{

int*a; // osoitin taulukkoon

system("chcp 1251");

scanf("%d", &n);

scanf("%d", &m);

// Muistin varaus

a = (int*) malloc(n*m*koko(int));

// Syötä taulukon elementit

for(i=0; i

for(j=0; j

printf("a[%d][%d] = ", i, j);

scanf("%d", (a+i*m+j));

// Näytä taulukon elementit

for(i=0; i

for(j=0; j

printf("%5d", *(a+i*m+j)); // 5 merkkiväliä taulukkoelementille

getchar(); getchar();
}

Toteutustulos

Syötä rivien määrä: 3

Syötä sarakkeiden lukumäärä: 4

On myös toinen tapa varata muistia dynaamisesti kaksiulotteiselle taulukolle - käyttämällä osoittimien ryhmää. Tätä varten tarvitset:
- varaa RAM-lohko osoittimien ryhmälle;
- allokoi RAM-lohkoja yksiulotteisille taulukoille, jotka ovat halutun matriisin rivejä;
- Kirjoita merkkijonojen osoitteet osoittimien joukkoon.

Malloc()-funktio palauttaa osoittimen dynaamisesti varatulta muistialueelta varatun kokoisen muistialueen ensimmäiseen tavuun. Jos dynaamisella muistialueella ei ole tarpeeksi muistia, palautetaan nollaosoitin.

#sisältää
#sisältää
#sisältää
void main()
{

int **a; // osoitin merkkijonoon

system("chcp 1251");

printf("Anna rivien määrä: ");

scanf("%d", &n);

printf("Anna sarakkeiden lukumäärä: ");

scanf("%d", &m);

// Varaa muistia merkkijonojen osoittimille

a = (int**)malloc(n*koko(int*));

// Syötä taulukon elementit

for(i=0; i

// Varaa muistia merkkijonojen tallentamista varten

a[i] = (int*)malloc(m*koko(int));

for(j=0; j

printf("a[%d][%d] = ", i, j);

scanf("%d", &a[i][j]);

// Näytä taulukon elementit

for(i=0; i

for(j=0; j

printf("%5d ", a[i][j]); // 5 merkkiväliä taulukkoelementille

ilmainen(a[i]); // muistin vapauttaminen merkkijonolle

getchar(); getchar();
}

Ohjelman suorituksen tulos on samanlainen kuin edellisessä tapauksessa.

Käyttämällä dynaamista muistin varausta merkkijonoosoittimille, voit varata vapaita taulukoita. vapaa kutsutaan kaksiulotteista taulukkoa (matriisia), jonka rivien koko voi olla erilainen. Vapaan taulukon käytön etuna on, että sinun ei tarvitse varata liikaa tietokoneen muistia pisimmän mahdollisen merkkijonon sijoittamiseksi. Itse asiassa vapaa matriisi on yksiulotteinen joukko osoittimia yksiulotteisiin tietotaulukoihin.

Osoittimet.

Osoitin on muuttuja, jonka arvo on osoite, jossa tiedot sijaitsevat. Osoite on sen muistipaikan numero, jossa tai jossa tiedot sijaitsevat.

SI:n tietotyypin mukaan osoittimet jaetaan:

Kirjoitettu osoitin on osoitin, joka sisältää tietyn tyyppisten tietojen (järjestelmän tai käyttäjän) osoitteen.

Kirjoittamaton osoitin on osoitin, joka sisältää määrittelemättömän tyyppisten tietojen osoitteen (vain osoitteen).

Osoitin ilmoitus;

Osoittimen asettaminen;

osoittimessa sijaitsevan arvon käyttäminen. Osoittimen ilmoitus (kuvaus) C-kielellä on seuraava:

Kirjoita *nimi [=arvo];

Osoitin SI:ssä voidaan alustaa ilmoittamalla määrittämällä vastaava arvo osoitusmerkin kautta. Tämän arvon on oltava jossakin seuraavista muodoista kirjoitettu osoite:

Nolla-arvo (NULL-tunniste);

Toinen osoitin;

Muuttuva osoite (osoitteen ottamista koskevan toiminnon kautta);

Osoitinaritmetiikkaa edustava lauseke;

Osoite, joka saadaan dynaamisen muistin varaamisesta.

#sisältää

int var; // säännöllinen kokonaislukumuuttuja

int *ptrVar; // kokonaislukuosoitin (ptrVar:n on oltava tyyppiä int, koska se viittaa int-tyypin muuttujaan)

ptrVar = // osoittanut osoittimelle sen solun osoitteen muistissa, jossa muuttujan var arvo on

scanf("%d", &var); // laita näppäimistöltä syötetty arvo muuttujaan var

printf("%d\n", *ptrVar); // Tulosta arvo osoittimen kautta

Toteutustulos: 6 6

Luento numero 3.

Toiminnot.

Funktio on syntaktisesti erotettu nimetty ohjelmamoduuli, joka suorittaa tietyn toiminnon tai toimintoryhmän. Jokaisella toiminnolla on oma käyttöliittymä ja toteutus. Funktiorajapinta - funktion otsikko, joka ilmaisee funktion nimen, sen parametrien luettelon ja palautusarvon tyypin.

Toiminnon kuvaus C-kielellä suoritetaan missä tahansa ohjelmassa muiden funktioiden kuvauksen ulkopuolella ja koostuu kolmesta elementistä:

1. toiminnon prototyyppi;

2. funktion otsikko;

3. kehon toiminta.

Toimintoprototyyppi on valinnainen osa toimintokuvausta, jonka tarkoituksena on ilmoittaa jokin toiminto, jonka käyttöliittymä vastaa tiettyä prototyyppiä. Prototyypin ilmoitus on seuraavanlainen:

Tyypin nimi (muodollisten parametrityyppien luettelo);

Funktioparametrit ovat arvoja, jotka välitetään funktiolle, kun sitä kutsutaan.

Funktiootsikko - funktion käyttöliittymäosan kuvaus, joka sisältää: palautustyypin, funktion nimen ja luettelon funktion muodollisista parametreista. Funktiootsikon ilmoitussyntaksi:

Tyypin nimi (muodollisten parametrien luettelo)

Esimerkkejä funktion otsikoista:

int funktio(int i, double x, double y)

void func(int ind, char *merkkijono)

Kaksoistoiminto (tyhjä)

Funktion runko on toteutusosa, joka sisältää ohjelmakoodin, joka suoritetaan, kun toimintoa kutsutaan. Funktioteksti seuraa aina heti funktion otsikon jälkeen (niitä ei voi erottaa) ja sulkeutuu aaltosulkeisiin.

SI:n funktion toteutus luvun kertoimen laskemiseksi.

double factorial (allekirjoittamaton);

Double factorial (allekirjoittamaton numero)

kaksoisfakta = 1,0;

For(signed i=1;i<=num;i++)

Fakta *= (kaksois)i;

palauttaa tosiasia;

rakenteet.

Rakenne on monimutkainen tietotyyppi, joka on joukko erityyppisiä elementtejä, jotka on järjestetty muistiin. Jokaisella rakenteen elementillä on oma nimi ja sitä kutsutaan kentällä.

Rakenteen SI-ilmoitus on:

Rakenne [tyypin nimi]

Kenttä_1;

Kenttä_2;

Kenttä_N;

) [muuttujien luettelo];

Rakennekentän ilmoitus on mahdollista vain ilman alustusta. Jos rakenteen kuvauksessa useat toisiaan seuraavat kentät ovat samaa tyyppiä, voidaan niitä kuvailla useiden samantyyppisten muuttujien ilmoittamiseen tarkoitetulla syntaksilla.

Tiedostot.

Tiedosto on nimetty tietoalue tallennusvälineellä. Tiedostotyypit (suhteessa "SI"-kieleen):
teksti;
binääri.
Tiedostoille suoritettavat perustoiminnot:
1. Tiedostojen avaaminen.
2. Tietojen lukeminen ja kirjoittaminen.
3. Tiedostojen sulkeminen.

Lisätoiminnot:
1.Navigointi tiedostossa.
2. Tiedostojen työskentelyn virheiden käsittely.
3.Poista ja nimeä uudelleen tiedostoja.
4. Muuttujan kuvaus

Avaustilat tiedostot SI:llä

Suoratoiston uudelleenohjaus
FILE * freopen(const char *tiedostonimi, const char *tila, FILE *virta);

Funktio palauttaa:
Tiedostoosoitin - kaikki on hyvin,
NULL on uudelleenmäärittelyvirhe.

Tiedoston sulkeminen
int fclose(TIEDOSTO *virta);

Funktio palauttaa:
0 - tiedosto suljettiin onnistuneesti.
1 - Tiedostoa suljettaessa tapahtui virhe.

Tiedoston lopun tarkistus
intfeof(TIEDOSTO*virta);
stream on osoitin avoimeen tiedostoon.

Funktio palauttaa:
0 - jos tiedoston loppua ei ole vielä saavutettu.
!0 – Tiedoston loppu saavutettu.

Tekstitiedostojen avaaminen
Toinen parametri määrittää lisäksi merkin t (valinnainen):
rt, wt, at, rt+, wt+, at+

Lukeminen tekstitiedostosta

Muotoiltu lukeminen
int fscanf(TIEDOSTO *virta, const char * muoto, ...);

Funktio palauttaa:
>0 – onnistuneesti luettujen muuttujien määrä,
0 - mitään muuttujista ei luettu onnistuneesti,
EOF - virhe tai tiedoston loppu saavutettu.
Rivin lukeminen

Funktio palauttaa:
puskuri - kaikki on hyvin,
Rivin lukeminen
char * fgets(char * puskuri, int maxlen, FILE *virta);

Funktio palauttaa:
puskuri - kaikki on hyvin,
NULL - virhe tai tiedoston loppu saavutettu.
Hahmon lukeminen
int fgetc(TIEDOSTO *virta);
Funktio palauttaa:
merkkikoodi - jos kaikki on hyvin,
EOF - jos tapahtuu virhe tai tiedoston loppu saavutetaan.
Hahmon palauttaminen streamiin
int ungetc(int c, TIEDOSTO *virta);
Funktio palauttaa:
merkkikoodi - jos kaikki onnistuu,
EOF Tapahtui virhe.

Kirjoita tekstiin tiedosto SI:ssä

Muotoiltu tulos
int fprintf(TIEDOSTO *virta, const char *muoto, ...);
Funktio palauttaa:
kirjoitettujen merkkien määrä - jos kaikki on kunnossa,
negatiivinen arvo - jos virhe.
Merkkijonon syöttö
int fputs(const char *merkkijono, TIEDOSTO *virta);
Funktio palauttaa:
kirjoitettujen merkkien määrä - kaikki on hyvin,
EOF Tapahtui virhe.
Symbolin syöttö
int fputc(int c, TIEDOSTO *virta);
Funktio palauttaa:
kirjoitetun merkin koodi - kaikki on kunnossa,
EOF Tapahtui virhe.
Binääritiedostojen avaaminen
Toinen parametri määrittää lisäksi merkin b (pakollinen): rb, wb, ab, rb+, wb+, ab+
Lukeminen binääritiedostoista
koko_t fread(void *puskuri, koko_t koko, koko_t numero,TIEDOSTO *virta);
Funktio palauttaa luettujen lohkojen määrän. Jos se on pienempi kuin num, tapahtui virhe tai
tiedoston loppu.

Kirjoittaminen binääritiedostoon
koko_t fwrite(const void *puskuri, koko_t koko, koko_t numero, TIEDOSTO *virta);
Funktio palauttaa kirjoitettujen lohkojen määrän. Jos se on pienempi kuin num, tapahtui virhe.

Tiedostonavigointi

Nykyisen siirtymän lukeminen tiedostossa:
pitkä int ftell(TIEDOSTO *virta);
Nykyisen siirtymän muuttaminen tiedostossa:
int fseek(TIEDOSTO *virta, pitkä int offset, int alkuperä);

SEEK_SET (0) - tiedoston alusta.
SEEK_CUR (1) - nykyisestä sijainnista.
SEEK_END (2) - tiedoston lopusta.
Funktio palauttaa:
0 - kaikki on hyvin,
!0 - tapahtui virhe.
Siirry tiedoston alkuun:
void rewind(FILE *stream);
Nykyisen sijainnin lukeminen tiedostossa:
int fgetpos(TIEDOSTO *virta, fpos_t *pos);
Nykyisen sijainnin asettaminen tiedostossa:
int fsetpos(TIEDOSTO *virta, const fpos_t *pos);
Toiminnot palauttavat:
0 - kaikki on onnistunut,
!0 - tapahtui virhe.
fpos_t rakenne:
typedef struct fpos_t (
kauan pois;
mbstate_t wstate;
) fpos_t;

Virheilmoituksen saaminen:
int ferror(TIEDOSTO *virta);
Funktio palauttaa nollasta poikkeavan arvon, jos tapahtui virhe.
Virheen palautustoiminto:
void clearerr(FILE *stream);
Virheviestin tulostustoiminto:
void perror(const char *merkkijono);

Puskurointi

Puskurin tyhjennystoiminto:
int flush(FILE *stream);
Funktio palauttaa:
0 - kaikki on hyvin.
EOF Tapahtui virhe.
Puskurin hallintatoiminto:
void setbuf(TIEDOSTO *virta, char * puskuri);

Luo puskurin, jonka koko on BUFSIZ. Käytetään ennen syöttämistä tai tulostusta streamiin.

Väliaikaiset tiedostot

Toiminto väliaikaisen tiedoston luomiseksi:
TIEDOSTO * tmpfile(void);
Luo väliaikaisen tiedoston wb+-tilassa. Kun tiedosto on suljettu, jälkimmäinen poistetaan automaattisesti.
Väliaikaisen tiedostonimen luontitoiminto:
char * tmpnam(char *puskuri);

Poista ja nimeä uudelleen

Tiedoston poistotoiminto:
int poista(const char *tiedostonimi);
Tiedoston uudelleennimeämistoiminto:
int rename(const char *fname, const char *nname);
Toiminnot palauttavat:
0 - onnistumisen tapauksessa
!0 muuten.

Luento numero 4.

Pino.

Pino on tavallaan jonon vastakohta, koska se toimii viimeisen sisään, ensin ulos (LIFO) -periaatteella. Jos haluat visualisoida pinon, ajattele lautaspinoa. Pöydän ensimmäinen lautanen käytetään viimeisenä ja viimeinen päälle asetettu lautanen käytetään ensimmäisenä. Pinoja käytetään usein järjestelmäohjelmistoissa, mukaan lukien kääntäjät ja tulkit.

Pinojen kanssa työskenneltäessä elementin lisääminen ja purkaminen ovat perustoiminnot. Näitä toimintoja kutsutaan perinteisesti "push onto the pino" (push) ja "pop pois pinosta" (pop). Siksi pinon toteuttamiseksi sinun on kirjoitettava kaksi funktiota: push(), joka työntää arvon pinoon, ja pop(), joka työntää arvon pois pinosta. On myös tarpeen varata muistialue, jota käytetään pinona. Tätä tarkoitusta varten voit varata taulukon tai dynaamisesti varata osan muistista käyttämällä dynaamiseen muistin varaamiseen tarkoitettuja C-kielen toimintoja. Kuten jonon kohdalla, hakutoiminto ottaa elementin luettelosta ja poistaa sen, jos sitä ei ole tallennettu muualle. Seuraava on push()- ja pop()-funktioiden yleinen muoto, jotka toimivat kokonaislukutaulukossa. Erityyppisiä tietopinoja voidaan järjestää muuttamalla taulukon taustalla olevaa tietotyyppiä.

inttos=0; /* pinon yläosa */

/* Työnnä elementti pinoon. */

void push (int i)

if(tos >= MAX) (

printf("Pino täynnä\n");

/* Hae pinon ylin elementti. */

jos(tos< 0) {

printf("Pino on tyhjä\n");

paluu pino;

Muuttuja tos ("top of stack") sisältää pinon yläosan indeksin. Näitä toimintoja toteutettaessa on otettava huomioon tapaukset, joissa pino on täynnä tai tyhjä. Meidän tapauksessamme tyhjän pinon etumerkki on tos yhtä suuri kuin nolla ja pinon ylivuodon etumerkki on sellainen tos-lisäys, että sen arvo osoittaa jonnekin taulukon viimeisen solun taakse.

Pino esimerkki.

Pino sijoitetaan dynaamisesti varattuun muistiin, ei kiinteän kokoiseen taulukkoon. Vaikka dynaamisen muistin allokoinnin käyttöä ei vaadita näin yksinkertaisessa esimerkissä, näemme kuinka käyttää dynaamista muistia pinotietojen tallentamiseen.

/* Yksinkertainen laskin, jossa on neljä vaihetta. */

#sisältää

#sisältää

int*p; /* osoitin vapaalle muistialueelle */

int *tos; /* osoitin pinon alkuun */

int*bos; /* osoitin pinon alaosaan */

void push(int i);

p = (int *) malloc(MAX*koko(int)); /* hanki pinomuisti */

printf("Virhe varattaessa muistia\n");

bos=p+MAX-1;

printf("Nelivaiheinen laskin\n");

printf("Poistu painamalla "q"\n");

printf("%d\n", a+b);

printf("%d\n", b-a);

printf("%d\n", b*a);

printf("Jako 0:lla.\n");

printf("%d\n", b/a);

tapaus ".": /* näyttää pinon yläosan sisällön */

printf("Nykyinen arvo pinon yläosassa: %d\n", a);

) while(*s != "q");

/* Elementin työntäminen pinoon. */

void push (int i)

jos(p > bos) (

printf("Pino täynnä\n");

/* Hae pinosta ylin elementti. */

jos (s< tos) {

printf("Pino on tyhjä\n");

Jonottaa.

Jono on lineaarinen luettelo tiedoista, joita käsitellään ensin sisään, ensin ulos -periaatteella; Tätä periaatetta (ja jonoa tietorakenteena) kutsutaan joskus myös FIFO:ksi. Tämä tarkoittaa, että ensimmäinen jonoon asetettu kohde on ensimmäinen, joka poistetaan jonosta, toinen jonoon asetettu kohde on toinen noudettava kohde ja niin edelleen. Tämä on ainoa tapa työskennellä jonon kanssa; satunnainen pääsy yksittäisiin elementteihin ei ole sallittu.

Jos haluat kuvitella jonon toiminnan, esittelemme kaksi funktiota: qstore() ja qretrieve() ("store" - "tallenna", "retrieve" - ​​"receive"). Funktio qstore() sijoittaa elementin jonon loppuun ja qretrieve()-funktio poistaa elementin jonon päästä ja palauttaa sen arvon. Taulukossa näkyy tällaisten toimintojen sarjan vaikutus.

Toiminta Jonon sisältö
qstore(A) A
qstore(B) A B
qstore(C) A B C
qretrieve() palauttaa A B C
qstore (D) B C D
qretrieve() palauttaa B C D
qretrieve() palauttaa C D

Huomaa, että hakutoiminto poistaa elementin jonosta ja tuhoaa sen, ellei sitä ole tallennettu muualle. Siksi, kun kaikki elementit on purettu, jono on tyhjä.

Ohjelmoinnissa jonoja käytetään monien ongelmien ratkaisemiseen. Yksi suosituimmista tällaisten ongelmien tyypeistä on simulointi. Jonoja käytetään myös käyttöjärjestelmän tehtävien ajoittajissa ja I/O-puskuroinnissa.

/* Minitapahtuman aikataulu */

#sisältää

#sisältää

#sisältää

#sisältää

char *p, *qretrieve(tyhjä);

void enter(void), qstore(char *q), review(void), delete_ap(void);

for(t=0; t< MAX; ++t) p[t] = NULL; /* иницилизировать массив

nollaosoittimet */

printf("Syötä (E), Lista (L), Poista (R), Poistu (Q): ");

*s = toupper(*s);

/* Lisää uusi kokous jonoon. */

void enter(void)

printf("Syötä tapaaminen %d: ", spos+1);

if(*s==0) ​​break; /* ei kirjoitettu */

p = (char *) malloc(strlen(s)+1);

printf("Muisti loppunut.\n");

if(*s) qstore(p);

/* Tarkastele jonon sisältöä. */

mitätön arvostelu (tyhjä)

for(t=rpos; t< spos; ++t)

printf("%d. %s\n", t+1, p[t]);

/* Poista kokous jonosta. */

void delete_ap(void)

if((p=qretrieve())==NULL) return;

printf("%s\n", p);

/* Lisää tapaaminen. */

void qstore(char*q)

printf("Lista täynnä\n");

/* Hae tapaaminen. */

char *qretrieve(tyhjä)

if(rpos==spos) (

printf("Älä kohtaa enää.\n");

paluu p;

Lista.

yksitellen linkitetty syklinen lista on rakenteiden rekursiivinen ilmoitus tai pikemminkin osoitin siihen itse tyyppirakenteessa:

int data;//tietokenttä

s *seuraava;//seuraava elementti

) *first,*curr;//ensimmäinen ja nykyinen elementti

Alustus:

ensimmäinen->seuraava=curr;

saadaksesi ensimmäisen elementin käytä first->data

lisätäksesi uuden elementin: curr->next=new s;

curr=curr->next;//siirry viimeiseen

ja saada esimerkiksi 50 elementti silmukan kautta listan yli:

curr=first;//siirry ensimmäiseen

for(int i=0;i<50;i++)

if(curr->ext!=NULL)

curr=curr->seuraava;


Samanlaisia ​​tietoja.


Ensimmäinen ajastin tällä sivustolla, joten tästä se lähtee.

Olen uusi C++:ssa ja työskentelen parhaillaan kirjan "Data Structures Using C++ 2nd ed, D.S. Malik" parissa.

Kirjassa Malik tarjoaa kaksi tapaa luoda dynaaminen kaksiulotteinen taulukko. Ensimmäisessä menetelmässä ilmoitat muuttujan osoittimien joukoksi, jossa jokainen osoitin on tyyppiä kokonaisluku. esim.

int *levy;

Ja sitten käytä for-silmukkaa luodaksesi "sarakkeita" samalla kun käytät osoittimia "riveinä".

Toinen tapa, käytät osoitinta osoittimeen.

Int **board; board = uusi int* ;

Kysymykseni kuuluu: mikä menetelmä on parempi? **-menetelmä on minulle helpompi visualisoida, mutta ensimmäistä menetelmää voidaan käyttää pitkälti samalla tavalla. Molempia menetelmiä voidaan käyttää dynaamisten 2D-taulukoiden luomiseen.

Edit: ei ollut tarpeeksi selkeä, kuten yllä kerroin. Tässä on kokeilemani koodi:

Int rivi, sarake; cout<< "Enter row size:"; cin >>rivi; cout<< "\ncol:"; cin >>col; int *p_board; for (int i=0; i< row; i++) p_board[i] = new int; for (int i=0; i < row; i++) { for (int j=0; j < col; j++) { p_board[i][j] = j; cout << p_board[i][j] << " "; } cout << endl; } cout << endl << endl; int **p_p_board; p_p_board = new int* ; for (int i=0; i < row; i++) p_p_board[i] = new int; for (int i=0; i < row; i++) { for (int j=0; j < col; j++) { p_p_board[i][j] = j; cout << p_p_board[i][j] << " "; } cout << endl; }

4 vastausta

Ensimmäistä menetelmää ei voida käyttää luomiseen dynaaminen 2D-taulukot, koska:

int *levy;

olet pohjimmiltaan varannut 4 osoittimen joukon int:lle pinossa. Joten jos täytät nyt jokaisen näistä neljästä osoittimesta dynaamisella taulukolla:

For (int i = 0; i< 4; ++i) { board[i] = new int; }

päädyt 2D-taulukkoon staattinen rivien lukumäärä (tässä tapauksessa 4) ja dynaaminen sarakkeiden lukumäärä (tässä tapauksessa 10). Näin ollen dynamiikka täysin, koska kun varaat taulukon pinossa, sinä on pakko osoittaa kiinteä koko, eli Tunnettu vuonna aika. Dynaaminen taulukkoa kutsutaan dynaaminen, koska sen kokoa ei tarvitse tietää kokoamisaika, vaan se voidaan määritellä jollakin muuttujalla in ajon aikana.

Vielä kerran kun teet:

int *levy;

Const int x = 4; //<--- `const` qualifier is absolutely needed in this case! int *board[x];

annat vakion, joka tunnetaan sisään kokoamisaika(tässä tapauksessa 4 tai x), jotta kääntäjä voi nyt esivalinta tämä muisti matriisillesi, ja kun ohjelmasi ladataan muistiin, sillä on jo sen verran muistia taulukkotaulukolle, minkä vuoksi sitä kutsutaan staattinen, eli koska koko kovakoodattu Ja ei voi muuttua dynaamisesti(suorituksen aikana).

Toisaalta, kun teet:

Int **board; board = uusi int*;

int x = 10; //<--- Notice that it does not have to be `const` anymore! int **board; board = new int*[x];

kääntäjä ei tiedä kuinka paljon muistia ryhmäkortti tarvitsee, joten se ei tiedä jakaa etukäteen Kaikki. Mutta kun suoritat ohjelmaa, taulukon koko määräytyy muuttujan x arvon mukaan (ajonaikaisesti), ja vastaava tila levytaulukolle varataan ns. kimppu- muistialue, johon kaikki tietokoneellasi käynnissä olevat ohjelmat voivat varata etukäteen tuntematon(kääntämishetkellä) kokonaismuistin henkilökohtaiseen käyttöön.

Tämän seurauksena dynaamisen 2D-taulukon luomiseksi sinun on käytettävä toista menetelmää:

Int **board; board = uusi int*; // dynaaminen taulukko (koko 10) osoittimista int for (int i = 0; i< 10; ++i) { board[i] = new int; // each i-th pointer is now pointing to dynamic array (size 10) of actual int values }

Loimme juuri 10 x 10 neliön 2D-taulukon. Voit käydä sen läpi ja täyttää sen todellisilla arvoilla, kuten 1, käyttämällä sisäkkäisiä silmukoita:

For (int i = 0; i< 10; ++i) { // for each row for (int j = 0; j < 10; ++j) { // for each column board[i][j] = 1; } }

Se, mitä kuvailet toiselle menetelmälle, antaa vain 1D-taulukon:

int *board = uusi int;

Tämä vain varaa taulukon, jossa on 10 elementtiä. Ehkä tarkoitit jotain tällaista:

Int **board = uusi int*; for (int i = 0; i< 4; i++) { board[i] = new int; }

Tässä tapauksessa varaamme 4 int* s, ja sitten jokainen osoittaa dynaamisesti allokoituun 10 int s:n taulukkoon.

Joten nyt vertaamme tätä int* boardiin; . Suurin ero on, että kun käytetään tällaista taulukkoa, "rivien" lukumäärä on tiedettävä käännöshetkellä. Tämä johtuu siitä, että taulukoilla oletetaan olevan kiinteät käännösaikakoot. Sinulla voi myös olla ongelma, jos haluat mahdollisesti palauttaa kyseisen taulukon int* s:sta, koska taulukko tuhoutuu sen laajuuden lopussa.

Menetelmä, joka varaa dynaamisesti sekä rivejä että sarakkeita, vaatii kehittyneempiä toimenpiteitä muistivuotojen välttämiseksi. Sinun on vapautettava muisti seuraavasti:

For (int i = 0; i< 4; i++) { delete board[i]; } delete board;

Suosittelen sen sijaan käyttämään vakiosäiliötä. Voit käyttää std::arraya 4> tai ehkä std::vektori > , jonka alustat sopivaan kokoon.

Molemmissa tapauksissa sisäinen ulottuvuutesi voidaan asettaa dynaamisesti (eli ottaa muuttujasta), mutta ero on ulkoisessa ulottuvuudessa.

Tämä kysymys vastaa periaatteessa seuraavaa:

on int* x = uusi int; "parempi" kuin int x?

Vastaus on "ei, ellei sinun tarvitse valita taulukon kokoa dynaamisesti."

Tämä koodi toimii hyvin harvojen ulkoisten kirjastovaatimusten kanssa ja näyttää int **array -muodon peruskäytön.

Tämä vastaus osoittaa, että matriisi jokainen on dynaamisesti kokoinen, ja myös kuinka dynaamisesti kokoinen lineaarinen matriisi määritetään dynaamisesti kokoiselle haarataulukolle.

Tämä ohjelma ottaa argumentit STDIN:stä seuraavassa muodossa:

2 2 3 1 5 4 5 1 2 8 9 3 0 1 1 3

Ohjelman koodi on alla...

#sisältää int main() ( int **taulukoiden_taulukko; int taulukoiden_määrä, kyselyiden_määrä; taulukoiden_määrä = kyselyiden_määrä = 0; std::cin >> numero_taulukot >> kyselyiden_määrä; //std::cout<< num_arrays << " " << num_queries; //Process the Arrays array_of_arrays = new int*; int size_current_array = 0; for (int i = 0; i < num_arrays; i++) { std::cin >> koko_nykyinen_taulukko; int *tmp_array = uusi int; for (int j = 0; j< size_current_array; j++) { int tmp = 0; std::cin >>tmp; tmp_array[j] = tmp; ) taulukoiden_taulukko[i] = tmp_taulukko; ) //Käsittele kyselyt int x, y; x=y=0; for (int q = 0; q< num_queries; q++) { std::cin >> x >> y; //std::out<< "Current x & y: " << x << ", " << y << "\n"; std::cout << array_of_arrays[x][y] << "\n"; } return 0; }

Tämä on hyvin yksinkertainen toteutus int main:sta ja riippuu vain std::cin:stä ja std::coutista. Bareboneja, mutta tarpeeksi hyvä osoittamaan, kuinka työskennellä yksinkertaisten moniulotteisten taulukoiden kanssa.