Kaksiulotteisen dynaamisen taulukon luominen kohdassa c. Kaksiulotteinen dynaaminen matriisi

Tyypillisesti muuttujan vaatima muistimäärä määritetään ennen käännösprosessia ilmoittamalla kyseinen muuttuja. Jos on tarvetta luoda muuttuja, jonka kokoa ei tiedetä etukäteen, käytetään dynaamista muistia. Varaus Ja vapautuminen C++-ohjelmien muistiongelmia voi ilmetä milloin tahansa. Operaatioita suoritetaan jakelu muisti kahdella tavalla:

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

Toiminto malloc varauksia vierekkäinen muistisolujen lohko tallennusta varten 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 tarkoitettu myös muistin varaamiseen. Alla oleva merkintä tarkoittaa, että se korostetaan nro elementtejä koko tavu.

void *calloc(nime, koko);

Tämä toiminto palauttaa osoittimen valitulle alueelle tai NULL kun on mahdotonta varata muistia. Toiminnon erikoisominaisuus on nollata kaikki valitut elementit.

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

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

Tässä s- osoitin muistialueelle, jonka koko on muutettava koko. Jos muistialueen osoite muuttuu funktion seurauksena, niin uusi osoite palaa tuloksena. Jos todellinen arvo ensimmäinen parametri NULL, sitten toiminto realloc toimii samalla tavalla kuin toiminto malloc eli se varaa kokoisen muistialueen koko tavu.

Käytä toimintoa vapauttaaksesi varatun muistin ilmainen. He puhuttelevat häntä näin:

void free (tyhjä *p koko);

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

Operaattorit uusi Ja poistaa vastaavia toimintoja malloc Ja ilmainen. Uusi varaa muistia, ja sen ainoa argumentti on lauseke, joka määrittää varattavien tavujen määrän. Operaattori palauttaa osoittimen varatun muistilohkon alkuun. Operaattori poistaa vapauttaa muistia, sen argumentti on lohkon ensimmäisen solun osoite, joka täytyy vapauttaa.

Dynaaminen matriisi- joukko vaihteleva pituus, jolle on varattu muistia ohjelman suorittamisen aikana. Muistin varaaminen tapahtuu funktioiden mukaan calloc, malloc tai operaattori uusi. Varatun muistipaikan ensimmäisen elementin osoite tallennetaan osoittimena ilmoitettuun muuttujaan. Esimerkiksi seuraava lause tarkoittaa, että osoitin on kuvattu mas ja sille annetaan viereisen alueen alun osoite dynaaminen muisti, korostettu operaattorilla uusi:

int *mas=uusi int;

Varatun muistin määrä riittää tallentamaan 10 int-arvoa.

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

Kun dynaaminen matriisi(milloin tahansa ohjelman käytön aikana) ei enää tarvita, niin muistia voidaan vapauttaa toiminnolla ilmainen tai operaattori poistaa.

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

Ongelma 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 koon syöttäminen //muistin varaaminen n reaalielementin joukolle a=(float *)malloc(n*sizeof(float)); cout<<"Введите массив A \n"; //ввод элементов массива for (i=0; i>*(a+i); ) //keräämällä taulukon elementtien summaa 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; //kirjoita taulukon koko

//varaa muistia n todellisen elementin 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);

//tulostaa summan arvon

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

//muistin vapauttaminen

ilmainen(a);

system("tauko");

paluu 0;

Ongelma 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; //kirjoita taulukon elementtien lukumäärä cout<<"n="; cin>>n; //muistin varaus int *a=uusi int[n]; cout<<"Введите элементы массива:\n"; //ввод массива for (i=0; i>a[i]; //tulostaa määritetyn taulukon kohteelle (i=0; i

//Esimerkki new- 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;

//kirjoita taulukon elementtien lukumäärä

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

//muistin varaus

int * a = uusi int [ n ] ;

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

//syöttötaulukko

Kun keräsin tietoja tämän artikkelin kirjoittamista varten, muistin ensimmäisen tutustumiseni osoittimiin - olin niin surullinen... Siksi, kun olin lukenut useita tätä aihetta käsitteleviä osia eri C++-ohjelmointia koskevista kirjoista, päätettiin valita eri reitti ja esitellä. C++-osoittimien aihe tarpeelliseksi katsomassani järjestyksessä. Annan sinulle lyhyen määritelmän heti ja tarkastelemme osoittimia toiminnassa esimerkkien avulla. Seuraavassa artikkelissa () hahmotellaan 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.

Seuraavien esimerkkien tarkastelun jälkeen ymmärrät pääasia - miksi tarvitsemme osoittimia ohjelmointiin, kuinka niitä deklaroidaan ja käytetään.

Oletetaan, että ohjelmassa meidän täytyy luoda kokonaislukutaulukko, jonka tarkkaa kokoa emme tiedä ennen ohjelman käynnistymistä. Toisin sanoen emme tiedä kuinka monta numeroa käyttäjän on syötettä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 – tämä saattaa riittää. Mutta älkäämme unohtako, että tämä ryhmä vie paljon tilaa RAM-muistista (5 000 * 4 (int-tyyppi) = 20 000 tavua). Olemme turvanneet itsemme, ja käyttäjä täyttää vain 10 taulukkoamme. Osoittautuu, että käytössä on itse asiassa 40 tavua ja 19 960 tavua tuhlaa muistia.

RAM-muistin kohtuuton käyttö

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

#sisältää

käyttäen nimiavaruutta std ;

int main()

> arrNumeroilla[i];

) cout

cout<< const int SizeOfArray = 5000 ;<< sizeof (arrWithDigits ) << " байт" << endl ;

int arrNummerilla [SizeOfArray] = ();

cout<< "Matriisi varattu muistiin";

int määrä = 0 ;

cout<< "Kuinka monta numeroa syötät taulukkoon?"<< amount * sizeof (int ) << " байт" << endl ;

cin >> määrä ;< amount ; i ++ )

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

"Todella tarpeellista"

cout<< endl ;

cin >> määrä ;< amount ; i ++ )

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

cout<< endl ;

paluu 0;

for (int i = 0 ; i cin >> arrNumeroilla [ i ] ; Tavalliseen kirjastotoimintoon koko() ilmoitetun taulukon ohittaminen arrNumeroilla rivi 10. Se palaa puhelun paikalle sen koon tavuina, jonka tämä taulukko varaa muistissa. Kysymykseen "Kuinka monta numeroa syötät taulukkoon?" vastaus on 10. Rivillä 15 lauseke määrä * 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 vaatii 40 tavua. Kuinka päästä eroon tästä tilanteesta? Joku saattaa haluta 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 ilmoittamista, emmekä voi pyytää sen syöttöä näppäimistöltä. Kokeile ja tarkista.


Tässä operaattori valaisee meidät punaisella >> koska vakioarvoa ei voi muuttaa.

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


Tässä meitä varoitetaan, että taulukon koko ei voi olla säännöllisen muuttujan arvo. Vakioarvo vaaditaan!

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

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

älykäs RAM-muistin käyttö osoittimien avulla

#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öttämä) cout<< "Чтобы создать массив чисел, введите его размер: "; cin >> sizeOfArray;< 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()

// HUOMIO! int* arrWithDigits - osoittimen määrittely // muistiin, jolle varataan uusi int* arrWithDigits = uusi int ;

for (int i = 0; i setlocale(LC_ALL, "rus");

cout<< int sizeOfArray = 0;;

// taulukon koko (käyttäjän syöttämä)

"Luo numerosarja antamalla sen koko: "

cin >> sizeOfArray ;

// HUOMIO! int* arrWithDigits - osoittimen ilmoitus

cin >> määrä ;< sizeOfArray ; i ++ )

// muistiin, jonka uusi varaa

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

cout<< endl ;

int * arrWithDigits = uusi int [ sizeOfArray ] ; arrNumeroilla[i] = i+1;

paluu 0;

poista arrWithDigits ; // muistin vapauttaminen Käyttäjä syöttää arvon näppäimistöltä - riviltä 12. Osoitin määritellään alla: int * arrNumeroilla Tämä merkintä tarkoittaa sitä int * arrNumeroilla arrNumeroilla * on osoitin. Se luodaan tallentamaan sen solun osoitteen, jossa kokonaisluku sijaitsee. Meidän tapauksessamme = osoittaa taulukon soluun, jonka indeksi on 0. Etumerkki uusi- sama kuin kertolaskussa. Kontekstin perusteella kääntäjä "ymmärtää", että tämä on osoittimen ilmoitus, ei kertolasku. Seuraavaksi tulee merkki ja operaattori, joka varaa osan muistista. Muistamme, että muistimme tulee varata taulukolle, ei yhdelle numerolle. Tallentaa uusi uusi int [sizeOfArray] voidaan tulkita näin:(kokonaislukujen tallentamiseen) (määrässä sizeOfArray ).

Siten rivillä 16 se määriteltiin dynaaminen matriisi. Tämä tarkoittaa, että muistia sille varataan (tai ei varata) ohjelman ollessa käynnissä, eikä kääntämisen aikana, kuten tavallisille taulukoille tapahtuu. Toisin sanoen muistin varaus riippuu ohjelman kehityksestä ja päätöksistä, jotka tehdään suoraan sen toiminnassa. Meidän tapauksessamme se riippuu siitä, mitä käyttäjä syöttää muuttujaan sizeOfArray

Rivi 25 käyttää operaattoria poistaa. Se vapauttaa varatun operaattorin uusi muisti. Koska uusi varattu muisti taulukon tallentamiseen, sitten kun vapautat sitä, sinun on tehtävä kääntäjälle selväksi, että on tarpeen vapauttaa taulukon muisti, ei vain sen nollasolu, joka on osoitettu int * arrNumeroilla. Siksi välillä poistaa ja osoittimen nimi sijoitetaan hakasulkeisiin poista arrWithDigits ; Muista, että joka kerta kun muistia varataan käyttämällä uusi, sinun on vapautettava tämä muisti käyttämällä poistaa. Tietenkin, kun ohjelma päättyy, sen käyttämä muisti vapautetaan automaattisesti. Mutta ota hyvä tapa käyttää operaattoreita uusi Ja poistaa pareittain. Loppujen lopuksi ohjelma voi sisältää esimerkiksi 5-6 taulukkoa. Ja jos vapautat muistia joka kerta, kun sitä ei enää tulevaisuudessa tarvita käynnissä olevassa ohjelmassa, muistia käytetään viisaammin.

Oletetaan, että ohjelmassamme täytimme matriisin kymmenellä arvolla. Seuraavaksi laskemme niiden summan ja kirjasimme sen johonkin muuttujaan. Ja siinä kaikki – emme enää työskentele tämän taulukon kanssa. Ohjelma jatkaa toimintaansa ja siihen luodaan uusia dynaamisia taulukoita johonkin tarkoitukseen. 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.

Tarkastellaan osoittimien käyttöä funktioiden parametreina. 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;<< "Введите новое значение второй переменной: "; cin >cout

#sisältää

#sisältää

käyttäen nimiavaruutta std ;

> varForCh2; )

int main()

// HUOMIO! int* arrWithDigits - osoittimen määrittely // muistiin, jolle varataan uusi int* arrWithDigits = uusi int ;

void changeData (int varForCh1 , int varForCh2 );

int muuttujaMuutos_1 = 0 ;

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

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

cout<< endl ;

int muuttujaMuutos_2 = 0 ;

cout<< endl ;

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

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

paluu 0;

muutosData(muuttujaMuutos_1, muuttujaMuutos_2);

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. Tämän seurauksena näet, että funktion suorittamisen jälkeen 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. Sitten toiminto pystyy työskentelemään suoraan muuttuvan tiedon kanssa osoitteessa. 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;<< "Введите новое значение второй переменной: "; cin >cout

> *varForCh2; ) Luennon tarkoitus

: opiskeluilmoitukset, muistin varaaminen ja purkaminen yksiulotteisille dynaamisille taulukoille, pääsy elementteihin, oppia ratkaisemaan ongelmia käyttämällä yksiulotteisia dynaamisia taulukoita C++-kielellä. Useita tietorakenteita käytettäessä käy usein niin, että niiden koko on muuttuva tietorakenteen koosta riippuen. läpimenoaika ohjelmia. Näissä tapauksissa on tarpeen käyttää dynaaminen muistin varaus

. Yksi yleisimmistä tällaisista tietorakenteista ovat taulukot, joiden kokoa ei ole alun perin määritelty tai kiinteä. Mukaan kielistandardi Taulukko on kokoelma elementtejä, joilla jokaisella on samat attribuutit. Kaikki nämä elementit sijoitetaan vierekkäisiin muistipaikkoihin riviin alkaen taulukon alkua vastaavasta osoitteesta. Toisin sanoen taulukon elementtien kokonaismäärä ja sille varatun muistin koko on täysin ja yksiselitteisesti määritelty taulukon määritelmässä. Mutta tämä ei ole aina kätevää. Joskus vaaditaan, että taulukolle varattu muisti on mitoitettu tietyn ongelman ratkaisemiseksi, eikä sen kokoa tiedetä etukäteen eikä sitä voida korjata. Vaihtelevan kokoisten taulukoiden (dynaamisten taulukoiden) muodostaminen voidaan järjestää osoittimien ja työkalujen avulla.

Dynaaminen matriisi dynaaminen muistin varaus on taulukko, jonka kokoa ei ole vahvistettu etukäteen ja joka voi muuttua ohjelman suorituksen aikana. Kokoa muuttamaan dynaaminen matriisi C++, joka tukee tällaisia ​​taulukoita, tarjoaa erityistä sisäänrakennetut toiminnot tai operaatioita. Dynaamiset taulukot tarjoavat mahdollisuuden joustavampaan työskentelyyn tietojen kanssa, koska niiden avulla ei voi ennustaa tallennettuja tietomääriä, vaan säätää taulukon kokoa todellisuudessa tarvittavien määrien mukaan.

Yksiulotteisten dynaamisten taulukoiden ilmoittaminen

Yksiulotteisen julistuksen mukaan on taulukko, jonka kokoa ei ole vahvistettu etukäteen ja joka voi muuttua ohjelman suorituksen aikana. Kokoa muuttamaan ymmärtää osoittimen määrittely tietyn tyyppiselle muuttujalle, jotta tätä muuttujaa voidaan käyttää dynaaminen matriisi.

Syntaksi:

Kirjoita *ArrayName;

Tyyppi – ilmoitettujen elementtien tyyppi on taulukko, jonka kokoa ei ole vahvistettu etukäteen ja joka voi muuttua ohjelman suorituksen aikana. Kokoa muuttamaan. Elementit on taulukko, jonka kokoa ei ole vahvistettu etukäteen ja joka voi muuttua ohjelman suorituksen aikana. Kokoa muuttamaan ei voi olla toimintoja ja elementtejä tyyppi tyhjä.

Esimerkiksi:

int *a; kaksinkertainen *d;

Näissä esimerkeissä a ja d ovat osoittimia varatun muistipaikan 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 osoitetaan varatun muistialueen alun osoitteen arvo.

Muistin varaaminen yksiulotteiselle dynaamiselle taulukolle

Muistin varaamiseksi yksiulotteiselle dynaaminen matriisi C++:ssa on kaksi tapaa.

1) operaatiolla new , joka varaa sopivan kokoisen osan dynaamisesta muistista taulukon tallentamista varten eikä salli taulukon elementtien alustamista.

Syntaksi:

ArrayName = uusi tyyppi [ConstantTypeExpression];

ArrayName – taulukon tunniste, eli varatun muistilohkon osoittimen nimi.

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

Esimerkiksi:

int *mas; mas = uusi int ; /*varaa dynaaminen muisti 100*(int) tavun koko*/ double *m = uusi tupla [n]; /*varaa n*(kaksois)tavun kokoinen dynaaminen muisti*/ pitkä (*lm); lm = uusi pitkä ; /*varaa dynaaminen muisti 2*4*(pitkien) tavujen koko*/

Kun allokoidaan dynaamista muistia, taulukon mitat on määritettävä täysin.

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 – taulukkoon johtavan osoittimen tyyppi.

N – taulukon elementtien lukumäärä.

Esimerkiksi:

kellua *a; a=(kelluke *)malloc(10*(kelluke)); // tai a=(float *)calloc(10,sizeof(float)); /*varaa dynaaminen muisti 10*(float) tavun koko*/

Koska malloc(calloc)-funktio palauttaa kirjoittamaton osoitin void * , niin tuloksena oleva tulos on muutettava

// 10 elementin kaksiulotteisen dynaamisen taulukon ilmoitus:

float **ptrarray = uusi float* ; // kaksi riviä 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 toisen asteen osoitin float **ptrarray, joka viittaa float* osoittimien joukkoon, jossa taulukon koko on kaksi . Tämän jälkeen for-silmukassa taulukon jokainen rivi ilmoitetaan in rivi 2 muistia on varattu viidelle elementille. Tuloksena on kaksiulotteinen dynaaminen taulukko ptraarray. Tarkastellaan esimerkkiä kaksiulotteiselle dynaamiselle taulukolle varatun muistin vapauttamisesta.

// kaksiulotteiselle dynaamiselle taulukolle varatun muistin vapauttaminen:

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

poista ptrarray;

// 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));

// Matriisielementtien syöttäminen

for(i=0; i

for(j=0; j

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

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

// Tulostaa taulukon elementtejä

for(i=0; i

for(j=0; j

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

getchar(); getchar();
}

Toteutustulos

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

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

Toinen tapa varata muistia dynaamisesti kaksiulotteiselle taulukolle on myös mahdollista - 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ä;
- kirjoittaa rivien osoitteet osoittimien joukkoon.

Malloc()-funktio palauttaa osoittimen dynaamisesti varatulta muistialueelta varatun kokoisen muistialueen ensimmäiseen tavuun. Jos kasassa 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);

// Muistin varaaminen osoittimille merkkijonoihin

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

// Matriisielementtien syöttäminen

for(i=0; i

// Muistin varaaminen 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]);

// Tulostaa taulukon elementtejä

for(i=0; i

for(j=0; j

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

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

getchar(); getchar();
}

Ohjelman suorittamisen tulos on samanlainen kuin edellisessä tapauksessa.

Käyttämällä dynaamista muistin varausta riviosoittimille voit varata vapaita taulukoita. Ilmainen on kaksiulotteinen taulukko (matriisi), jonka rivien koko voi olla erilainen. Vapaan taulukon käytön etuna on, että sinun ei tarvitse varata liikaa tietokoneen muistia maksimipituisen merkkijonon sijoittamiseen. Itse asiassa vapaa matriisi on yksiulotteinen joukko osoittimia yksiulotteisiin tietotaulukoihin.

Osoittimet.

Osoitin on muuttuja, jonka arvo on osoite, jossa tiedot sijaitsevat. Osoite on sen muistisolun numero, jossa tai josta 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 tyyppisen dataosoitteen (vain osoitteen).

Osoitin ilmoitus;

Osoittimen asettaminen;

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

Kirjoita *nimi [=arvo];

Kun osoitin on ilmoitettu, SI:n osoitin voidaan alustaa osoittamalla vastaava arvo määritysmerkin avulla. Tämän arvon on oltava osoite, joka on kirjoitettu jollakin seuraavista muodoista:

Nolla (id NULL);

Toinen osoitin;

Muuttuva osoite (osoitteen ottamista koskevan toiminnan kautta);

Lauseke, joka edustaa osoittimen aritmetiikkaa;

Osoite, joka on dynaamisen muistin varauksen tulos.

#sisältää

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

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

ptrVar = // antoi osoittimelle sen muistisolun osoitteen, jossa muuttujan var arvo sijaitsee

scanf("%d", &var); // muuttuja var sisältää näppäimistöltä syötetyn arvon

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

Toteutustulos: 6 6

Luento nro 3.

Toiminnot.

Funktio on syntaktisesti tunnistettu nimetty ohjelmamoduuli, joka suorittaa tietyn toiminnon tai toimintoryhmän. Jokaisella toiminnolla on oma käyttöliittymä ja toteutus. Funktiorajapinta – funktion otsikko, joka määrittää funktion nimen, luettelon sen parametreista ja palautusarvon tyypin.

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

1. toiminnon prototyyppi;

2. funktion otsikko;

3. kehon toiminta.

Toiminnon prototyyppi on valinnainen osa toimintokuvausta, jonka tarkoituksena on ilmoittaa toiminto, jonka käyttöliittymä vastaa tiettyä prototyyppiä.

Tyypin nimi (muodollisten parametrityyppien luettelo);

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

Funktiootsikko on kuvaus funktion käyttöliittymäosasta, joka sisältää: palautusarvon tyypin, funktion nimen ja luettelon funktion muodollisista parametreista. Funktiootsikon ilmoittamisen syntaksi on:

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 funktiota kutsutaan. Toimintokappale tulee aina välittömästi toimintopään jälkeen (ei voi erottaa toisistaan) ja se on suljettu kiharaisiin hakasulkeisiin.

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;

Palautus tosiasia;

Rakenteet.

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

Rakenteen SI-ilmoitus näyttää tältä:

Rakenne [tyypin nimi]

Kenttä_1;

Kenttä_2;

Kenttä_N;

   ) [muuttujien luettelo];

Rakennekenttien ilmoittaminen on mahdollista vain ilman alustusta. Jos rakennekuvauksessa useat toisiaan seuraavat kentät ovat samaa tyyppiä, niiden kuvaamiseen voidaan käyttää syntaksia useiden samantyyppisten muuttujien ilmoittamiseen.

Tiedostot.

Tiedosto on nimetty tietoalue jollain 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. Tiedostonavigointi.
2. Virheiden käsittely tiedostojen käsittelyssä.
3. Tiedostojen poistaminen ja uudelleennimeäminen.
4.Muuttujan kuvaus

Avaustilat tiedostot SI:llä

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

Funktio palauttaa:
  Osoitin tiedostoon - kaikki on hyvin,
  NULL – ohitusvirhe.

Tiedoston sulkeminen
  int fclose(TIEDOSTO *virta);

Funktio palauttaa:
  0 – tiedosto suljettiin onnistuneesti.
  1 – tiedostoa suljettaessa tapahtui virhe.

Tiedoston lopputarkistus
  int feof(TIEDOSTO *virta);
  stream - 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.
Symbolin lukeminen
  int fgetc(TIEDOSTO *virta);
Funktio palauttaa:
  symbolikoodi - jos kaikki on hyvin,
  EOF – jos tapahtui virhe tai tiedoston loppu saavutettiin.
Hahmon laittaminen takaisin streamiin
  int ungetc(int c, TIEDOSTO *virta);
Funktio palauttaa:
  symbolikoodi – jos kaikki onnistuu,
  EOF – tapahtui virhe.

Kirjoita tekstiin SI-tiedosto

Muotoiltu tulos
  int fprintf(TIEDOSTO *virta, const char *muoto, ...);
Funktio palauttaa:
  kirjoitettujen merkkien määrä - jos kaikki on normaalia,
  negatiivinen arvo – jos on virhe.
Kirjoittaa merkkijonoa
  int fputs(const char *merkkijono, TIEDOSTO *virta);
Funktio palauttaa:
  kirjoitettujen merkkien määrä - kaikki on hyvin,
  EOF – tapahtui virhe.
Kirjoita symboli
  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, on tapahtunut tai saavutettu virhe
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;

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

Puskurointi

Puskurin tyhjennystoiminto:
  int flush(TIEDOSTO *virta);
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 tuloa tai tulostusta streamiin.

Väliaikaiset tiedostot

Väliaikainen tiedoston luontitoiminto:
  TIEDOSTO * tmpfile(void);
Luo väliaikaisen tiedoston wb+-tilassa. Tiedoston sulkemisen jälkeen jälkimmäinen poistetaan automaattisesti.
Väliaikaisen tiedostonimen luontitoiminto:
  char * tmpnam(char *puskuri);

Poistaminen ja uudelleennimeäminen

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

Luento nro 4.

Pino.

Pino on jonon vastakohta, koska se toimii LIFO-periaatteella. Jos haluat visualisoida pinon, ajattele lautaspinoa. Ensimmäinen pöydälle asetettu lautanen käytetään viimeisenä ja viimeinen pöydä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äys- ja palautustoiminnot ovat tärkeimpiä. Näitä toimintoja kutsutaan perinteisesti "push"- ja "pop". Siksi pinon toteuttamiseksi sinun on kirjoitettava kaksi funktiota: push(), joka "työntää" arvon pinoon, ja pop(), joka "poppaa" arvon pinosta. Sinun on myös varattava 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 jonossa, hakutoiminto ottaa elementin luettelosta ja poistaa sen, jos sitä ei ole jo tallennettu muualle. Alla on push()- ja pop()-funktioiden yleinen muoto, jotka toimivat kokonaislukutaulukossa. Muun tyyppisiä tietopinoja voidaan järjestää muuttamalla taulukon taustalla olevaa tietotyyppiä.

int tos=0; /* pinon yläosa */

/* Työnnä elementti pinoon. */

void push (int i)

if(tos >= MAX) (

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

/* Hae pinon ylin elementti. */

jos(tos< 0) {

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

paluu pino;

Tos-muuttuja ("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 merkki on, että tos on nolla, ja pinon ylivuodon merkki on, että tos kasvaa niin paljon, että sen arvo osoittaa jonnekin taulukon viimeisen solun taakse.

Esimerkki pinon kanssa työskentelystä.

Pino sijoitetaan dynaamisesti varattuun muistiin, ei kiinteän kokoiseen taulukkoon. Vaikka dynaamisen muistin allokoinnin käyttäminen ei ole välttämätöntä 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 yläosaan */

int *bos; /* osoitin pinon alaosaan */

void push(int i);

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

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("Jaa 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 on täynnä\n");

/* Hae pinosta ylin elementti. */

jos (s< tos) {

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

Jonottaa.

Jono on lineaarinen luettelo tiedoista, jotka 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 elementti vastaanotetaan siitä ensin, toinen asetettu elementti poistetaan toisena jne. Tämä on ainoa tapa työskennellä jonon kanssa; satunnainen pääsy yksittäisiin elementteihin ei ole sallittu.

Jos haluat kuvitella, miten jono toimii, esitellään kaksi funktiota: qstore() ja qretrieve() ("store" - "tallenna", "retrieve" - ​​"receive"). Funktio qstore() sijoittaa elementin jonon loppuun ja qretrieve()-funktio poistaa elementin jonon alusta ja palauttaa sen arvon. Taulukko näyttää tällaisten toimintojen järjestyksen.

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:n C D
qretrieve() palauttaa C D

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

Ohjelmoinnissa jonoja käytetään monien ongelmien ratkaisemiseen. Yksi suosituimmista tällaisten tehtävien 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; /* иницилизировать массив

tyhjät osoittimet */

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

*s = toupper(*s);

/* Lisää uusi tapaaminen jonoon. */

void enter(void)

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

if(*s==0) ​​break; /* äänitystä ei tehty */

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

printf("Muisti ei riitä.\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]);

/* Tapaamisen poistaminen 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("Ei enää kokousta.\n");

paluu p;

Lista.

Yksittäin 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 saadaksesi esimerkiksi 50. elementin, selaa luetteloa:

curr=first;//siirry ensimmäiseen

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

if(curr->seuraava!=NULL)

curr=curr->seuraava;


Aiheeseen liittyvää tietoa.


Ensimmäinen ajastin tällä sivustolla, joten se menee tänne.

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ä määrität muuttujan osoittimien joukoksi, jossa jokainen osoitin on tyyppiä kokonaisluku. esim

Int *levy;

Ja käytä sitten 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 2-ulotteisten taulukoiden luomiseen.

Edit: ei ollut tarpeeksi selkeä, kuten yllä kerroin. Tässä koodi, jota kokeilin:

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 pinoa kohti. Joten jos täytät nyt jokainen näistä neljästä osoittimesta dynaamisella taulukolla:

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

päädyt 2D-taulukkoon staattinen rivien määrä (tässä tapauksessa 4) ja dynaaminen sarakkeiden lukumäärä (tässä tapauksessa 10). Dynamiikka ei siis ole täysin, koska kun varaat taulukon pinoon pitäisi osoittaa vakiokoko, eli Tunnettu vuonna aika. Dynaaminen taulukkoa kutsutaan dynaaminen, koska sen kokoa ei tarvitse tietää kokoamisaika, vaan se voidaan määritellä jollakin muuttujalla in toteutuksen 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 tämän verran muistia levytaulukolle, minkä vuoksi sitä kutsutaan staattinen, eli koska koko kovakoodattu Ja ei voi muuttua dynaamisesti(ajon 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 levyryhmä vaatii, 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. joukko- muistialue, johon kaikki tietokoneellasi käynnissä olevat ohjelmat voivat varautua tuntematon etukäteen(kääntämishetkellä) tiivistää muistin 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 }

Olemme juuri luoneet 10 x 10 neliön 2D-taulukon. Sen läpikäymiseksi ja sen täyttämiseksi todellisilla arvoilla, kuten 1, voisimme käyttää 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ä kuvaat toiselle menetelmälle, tuottaa vain 1D-taulukon:

Int *board = uusi int;

Tämä yksinkertaisesti 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 allokoimme 4 int* s ja sitten jokainen piste 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 on oltava kiinteät käännösajan koot. Sinulla voi myös olla ongelma, jos haluat ehkä palauttaa tämän taulukon int* s:sta, koska taulukko tuhoutuu sen laajuuden lopussa.

Menetelmä, joka varaa dynaamisesti sekä rivejä että sarakkeita, vaatii monimutkaisempia toimenpiteitä muistivuotojen välttämiseksi. Sinun pitäisi vapauttaa muisti seuraavasti:

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

Minun on suositeltavaa käyttää tavallista säiliötä sen sijaan. Voit käyttää std::arraya 4> tai ehkä std::vektori > jonka alustat sopivalla koolla.

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

Tämä kysymys vastaa periaatteessa seuraavaa:

Onko 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 ** -taulukon peruskäytön.

Tämä vastaus osoittaa, että matriisi jokainen on dynaaminen koko 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;< size_current_array; j++) { int tmp = 0; std::cin >int *tmp_array = uusi int;< num_queries; q++) { std::cin >for (int j = 0; j<< "Current x & y: " << x << ", " << y << "\n"; std::cout << array_of_arrays[x][y] << "\n"; } return 0; }

>tmp;