Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
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 int
hatá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ó:
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 cout
utasí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 szError1
első 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;