Megosztás a következőn keresztül:


Tömbök (C++)

A tömbök olyan azonos típusú objektumok sorozatai, amelyek egy összefüggő memóriaterületet foglalnak el. A hagyományos C stílusú tömbök számos hiba forrását képezik, de továbbra is gyakoriak, különösen a régebbi kódbázisokban. A modern C++-ban erősen javasoljuk, hogy az ebben a szakaszban ismertetett C stílusú tömböket használja std::vector vagy std::array helyettük. Mindkét standard kódtártípus egybefüggő memóriablokkként tárolja az elemeket. Azonban nagyobb típusbiztonságot biztosítanak, és támogatják az iterátorokat, amelyek garantáltan egy érvényes helyre mutatnak a sorozaton belül. További információ: Tárolók.

Stack deklarációk

Egy C++ tömbdeklarációban a tömbméret a változó neve után van megadva, nem pedig a típus neve után, mint más nyelvekben. Az alábbi példa deklarál egy tömböt 1000 double típusú elemmel, amely a veremben lesz lefoglalva. Az elemek számát egész számkonstansként vagy állandó kifejezésként kell megadni. Ennek az az oka, hogy a fordítónak tudnia kell, hogy mennyi veremmemóriát kell lefoglalnia; nem használhat futásidőben kiszámított értéket. A tömb minden eleme 0 alapértelmezett értéket kap. Ha nem rendel hozzá alapértelmezett értéket, az egyes elemek kezdetben bármilyen véletlenszerű értéket tartalmaznak, amelyek az adott memóriahelyen történnek.

    constexpr size_t size = 1000;

    // Declare an array of doubles to be allocated on the stack
    double numbers[size] {0};

    // Assign a new value to the first element
    numbers[0] = 1;

    // Assign a value to each subsequent element
    // (numbers[1] is the second element in the array.)
    for (size_t i = 1; i < size; i++)
    {
        numbers[i] = numbers[i-1] * 1.1;
    }

    // Access each element
    for (size_t i = 0; i < size; i++)
    {
        std::cout << numbers[i] << " ";
    }

A tömb első eleme a nulladik elem. Az utolsó elem az (n-1) elem, ahol n az elemek száma, amelyet a tömb tartalmazhat. A deklaráció elemeinek száma integrál típusúnak kell lennie, és 0-nál nagyobbnak kell lennie. Az Ön felelőssége annak biztosítása, hogy a program soha ne adjon át értéket az index operátornak, amely nagyobb, mint (size - 1).

A nulla méretű tömb csak akkor legális, ha a tömb az utolsó mező egy struct vagy union szerkezetben, és amikor a Microsoft-bővítmények engedélyezve vannak (amikor /Za vagy /permissive- nincs engedélyezve).

A halomalapú tömbök gyorsabban foglalhatók le és érhetők el, mint a halomalapú tömbök. A veremterület azonban korlátozott. A tömbelemek száma nem lehet olyan nagy, hogy túl sok veremmemóriát használ fel. Az, hogy mi számít túl soknak, a programtól függ. Profilkészítési eszközökkel megállapíthatja, hogy egy tömb túl nagy-e.

Halom deklarációk

Előfordulhat, hogy olyan tömbre van szükség, amely túl nagy a verem memóriában való elhelyezéshez, vagy amelynek mérete fordításkor nem ismert. Ezt a tömböt egy kifejezéssel new[] lefoglalhatja a halomra. Az operátor egy mutatót ad vissza az első elemhez. Az indexelő operátor ugyanúgy működik a mutatóváltozón, mint egy veremalapú tömbön. A mutató aritmetikai használatával is áthelyezheti a mutatót a tömb tetszőleges elemeire. Az Ön felelőssége, hogy:

  • Mindig megtartja az eredeti mutatócím másolatát, így törölheti a memóriát, ha már nincs szüksége a tömbre.
  • a mutatócímet nem növekményesen vagy decrementálhatja a tömbhatárokon túlra.

Az alábbi példa bemutatja, hogyan definiálhat tömböt a halomban futási idő alatt. Bemutatja, hogyan érheti el a tömbelemeket az alsó index operátorral és a mutató aritmetikai használatával:

void do_something(size_t size)
{
    // Declare an array of doubles to be allocated on the heap
    double* numbers = new double[size]{ 0 };

    // Assign a new value to the first element
    numbers[0] = 1;

    // Assign a value to each subsequent element
    // (numbers[1] is the second element in the array.)
    for (size_t i = 1; i < size; i++)
    {
        numbers[i] = numbers[i - 1] * 1.1;
    }

    // Access each element with subscript operator
    for (size_t i = 0; i < size; i++)
    {
        std::cout << numbers[i] << " ";
    }

    // Access each element with pointer arithmetic
    // Use a copy of the pointer for iterating
    double* p = numbers;

    for (size_t i = 0; i < size; i++)
    {
        // Dereference the pointer, then increment it
        std::cout << *p++ << " ";
    }

    // Alternate method:
    // Reset p to numbers[0]:
    p = numbers;

    // Use address of pointer to compute bounds.
    // The compiler computes size as the number
    // of elements * (bytes per element).
    while (p < (numbers + size))
    {
        // Dereference the pointer, then increment it
        std::cout << *p++ << " ";
    }

    delete[] numbers; // don't forget to do this!

}
int main()
{
    do_something(108);
}

Tömbök inicializálása

Egy tömböt inicializálhat egy ciklusban, egyszerre egy elemet, vagy egyetlen utasítással. A következő két tömb tartalma megegyezik:

    int a[10];
    for (int i = 0; i < 10; ++i)
    {
        a[i] = i + 1;
    }

    int b[10]{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

Tömbök átadása függvényeknek

Amikor egy tömböt átadunk egy függvénynek, azt mutatóként adják át az első elemére, függetlenül attól, hogy veremalapú vagy halomalapú tömbről van-e szó. A mutató nem tartalmaz más méret- és típusadatokat. Ezt a viselkedést mutatórohadásnak nevezzük. Ha tömböt ad át egy függvénynek, mindig meg kell adnia egy külön paraméter elemeinek számát. Ez a viselkedés azt is jelenti, hogy a tömbelemek nem lesznek másolva, amikor a tömb átadódik egy függvénynek. Ha meg szeretné akadályozni, hogy a függvény módosítsa az elemeket, adja meg a paramétert az elemekre const mutató mutatóként.

Az alábbi példa egy tömböt és egy hosszt elfogadó függvényt mutat be. Az egérmutató az eredeti tömbre mutat, nem másolatra. Mivel a paraméter nem const, a függvény módosíthatja a tömbelemeket.

void process(double *p, const size_t len)
{
    std::cout << "process:\n";
    for (size_t i = 0; i < len; ++i)
    {
        // do something with p[i]
    }
}

Deklarálja és határozza meg a p tömbparamétert const-ként, hogy a függvényblokkon belül írásvédett legyen.

void process(const double *p, const size_t len);

Ugyanez a függvény is deklarálható ilyen módon, és nem változik a viselkedése. A tömb továbbra is az első elem mutatójaként lesz átadva:

// Unsized array
void process(const double p[], const size_t len);

// Fixed-size array. Length must still be specified explicitly.
void process(const double p[1000], const size_t len);

Többdimenziós tömbök

A más tömbökből létrehozott tömbök többdimenziós tömbök. Ezek a többdimenziós tömbök több szögletes állandó kifejezés egymás utáni elhelyezésével vannak megadva. Vegyük például ezt a deklarációt:

int i2[5][7];

Egy típustömböt inthatároz meg, amely elméletileg öt sorból és hét oszlopból álló kétdimenziós mátrixban van elrendezve, ahogyan az alábbi ábrán látható:

Többdimenziós tömb elméleti elrendezése.

A kép egy rács, amely 7 mező széles és 5 mező magas. Minden cella tartalmazza a cella indexét. Az első cellaindex címkéje 0,0. A soron következő cella a 0,1, és így tovább a sor utolsó cellájára, amely 0,6. A következő sor az 1,0 indexkel kezdődik. Az azt követő cella indexe 1,1. Az utolsó cella a sorban 1,6. Ez a minta az utolsó sorig ismétlődik, amely a 4,0 indexkel kezdődik. Az utolsó sorban lévő utolsó cella indexe 4,6.

Deklarálhat többdimenziós tömböket, amelyek inicializálólistával rendelkeznek (az Inicializálókban leírtak szerint). Ezekben a deklarációkban az első dimenzió határait meghatározó állandó kifejezés kihagyható. Például:

// arrays2.cpp
// compile with: /c
const int cMarkets = 4;
// Declare a float that represents the transportation costs.
double TransportCosts[][cMarkets] = {
   { 32.19, 47.29, 31.99, 19.11 },
   { 11.29, 22.49, 33.47, 17.29 },
   { 41.97, 22.09,  9.76, 22.55 }
};

Az előző deklaráció egy három sorból négy oszlopból álló tömböt határoz meg. A sorok gyárakat jelölnek, az oszlopok pedig azokat a piacokat jelölik, amelyekre a gyárak szállnak. Az értékek a szállítási költségek a gyáraktól a piacokig. A tömb első dimenziója elmarad, de a fordítóprogram kitölti az inicializáló vizsgálatával.

Az indirekt operátor (*) használata n dimenziós tömbtípuson n-1 dimenziós tömböt eredményez. Ha n értéke 1, egy skaláris érték (vagy tömbelem) lesz az eredménye.

A C++ tömbök sorszintű sorrendben vannak tárolva. A sorfolyamatos elrendezés azt jelenti, hogy az utolsó index változik a leggyorsabban.

példa

A függvénydeklarációkban a többdimenziós tömb első dimenziójának kötöttségi specifikációját is kihagyhatja, ahogy az itt látható:

// multidimensional_arrays.cpp
// compile with: /EHsc
// arguments: 3
#include <limits>   // Includes DBL_MAX
#include <iostream>

const int cMkts = 4, cFacts = 2;

// Declare a float that represents the transportation costs
double TransportCosts[][cMkts] = {
   { 32.19, 47.29, 31.99, 19.11 },
   { 11.29, 22.49, 33.47, 17.29 },
   { 41.97, 22.09,  9.76, 22.55 }
};

// Calculate size of unspecified dimension
const int cFactories = sizeof TransportCosts /
                  sizeof( double[cMkts] );

double FindMinToMkt( int Mkt, double myTransportCosts[][cMkts], int mycFacts);

using namespace std;

int main( int argc, char *argv[] ) {
   double MinCost;

   if (argv[1] == 0) {
      cout << "You must specify the number of markets." << endl;
      exit(0);
   }
   MinCost = FindMinToMkt( *argv[1] - '0', TransportCosts, cFacts);
   cout << "The minimum cost to Market " << argv[1] << " is: "
       << MinCost << "\n";
}

double FindMinToMkt(int Mkt, double myTransportCosts[][cMkts], int mycFacts) {
   double MinCost = DBL_MAX;

   for( size_t i = 0; i < cFacts; ++i )
      MinCost = (MinCost < TransportCosts[i][Mkt]) ?
         MinCost : TransportCosts[i][Mkt];

   return MinCost;
}
The minimum cost to Market 3 is: 17.29

A függvény FindMinToMkt úgy van megírva, hogy az új gyárak hozzáadása nem igényel kódmódosítást, csak egy újrafordítást.

Tömbök inicializálása

Az osztálykonstruktort tartalmazó objektumtömböket a konstruktor inicializálja. Ha az inicializáló listában kevesebb elem szerepel, mint a tömb elemei, a rendszer az alapértelmezett konstruktort használja a többi elemhez. Ha nincs megadva alapértelmezett konstruktor az osztályhoz, az inicializálók listájának teljesnek kell lennie, vagyis a tömb minden eleméhez egy inicializálónak kell lennie.

Vegye figyelembe a Point két konstruktort meghatározó osztályt:

// initializing_arrays1.cpp
class Point
{
public:
   Point()   // Default constructor.
   {
   }
   Point( int, int )   // Construct from two ints
   {
   }
};

// An array of Point objects can be declared as follows:
Point aPoint[3] = {
   Point( 3, 3 )     // Use int, int constructor.
};

int main()
{
}

Az első elem aPoint a konstruktor Point( int, int )használatával jön létre; a fennmaradó két elem az alapértelmezett konstruktor használatával jön létre.

A statikus tagtömbök (függetlenül attól, hogy const vagy sem) inicializálhatók a definíciójukban (az osztálydeklaráción kívül). Például:

// initializing_arrays2.cpp
class WindowColors
{
public:
    static const char *rgszWindowPartList[7];
};

const char *WindowColors::rgszWindowPartList[7] = {
    "Active Title Bar", "Inactive Title Bar", "Title Bar Text",
    "Menu Bar", "Menu Bar Text", "Window Background", "Frame"   };
int main()
{
}

Tömbelemek elérése

A tömb egyes elemeit a tömb alsó index operátorával ([ ]) érheti el. Ha egy egydimenziós tömb nevét használja alsó index nélkül, az a tömb első elemére mutató mutatóként lesz kiértékelve.

// using_arrays.cpp
int main() {
   char chArray[10];
   char *pch = chArray;   // Evaluates to a pointer to the first element.
   char   ch = chArray[0];   // Evaluates to the value of the first element.
   ch = chArray[3];   // Evaluates to the value of the fourth element.
}

Többdimenziós tömbök használata esetén különböző kombinációkat használhat a kifejezésekben.

// using_arrays_2.cpp
// compile with: /EHsc /W1
#include <iostream>
using namespace std;
int main() {
   double multi[4][4][3];   // Declare the array.
   double (*p2multi)[3];
   double (*p1multi);

   cout << multi[3][2][2] << "\n";   // C4700 Use three subscripts.
   p2multi = multi[3];               // Make p2multi point to
                                     // fourth "plane" of multi.
   p1multi = multi[3][2];            // Make p1multi point to
                                     // fourth plane, third row
                                     // of multi.
}

Az előző kódban a multi egy háromdimenziós tömb, amely double típusú. Az p2multi egérmutató egy három méretű double tömbre mutat. Ebben a példában a tömböt egy-, két- és három-indexekkel használjuk. Bár gyakoribb az összes alsó index megadása, mint az cout utasításban, néha hasznos a tömbelemek egy adott részhalmazának kiválasztása, ahogyan az az alábbi coututasításokban is látható.

Túlterhelési indexelő operátor

A többi operátorhoz hasonlóan az alsó index operátor ([]) is újradefiniálható a felhasználó által. Az alsó index operátor alapértelmezett viselkedése, ha nincs túlterhelve, a tömb nevét és az alsó indexet az alábbi módszerrel kombinálja:

*((array_name) + (subscript))

Amint az összes olyan összeadásnál, amely mutatótípusokat foglal magában, a méretezés automatikusan megtörténik a típus méretének beállításához. Az eredményül kapott érték nem az n bájt a tömb kezdetétől array_name, hanem a tömb n. eleme. Az átalakításról további információt az Additív operátorok című témakörben talál.

A többdimenziós tömbökhöz hasonlóan a cím a következő módszerrel származtatható:

((array_name) + (subscript1 * max2 * max3 * ... * maxn) + (subscript2 * max3 * ... * maxn) + ... + subscriptn))

Tömbök a kifejezésekben

Ha egy tömbtípus azonosítója nem , cím (sizeof) vagy hivatkozás inicializálása kifejezésben &jelenik meg, akkor a rendszer az első tömbelemre mutatóvá alakítja. Például:

char szError1[] = "Error: Disk drive not ready.";
char *psz = szError1;

Az egérmutató psz a tömb szError1első elemére mutat. A tömbök a mutatókkal ellentétben nem módosítható l-értékek. Ezért érvénytelen a következő hozzárendelés:

szError1 = psz;

Lásd még

std::array