Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Pole je posloupnost objektů stejného typu, které zabírají souvislou oblast paměti. Tradiční pole ve stylu jazyka C jsou zdrojem mnoha chyb, ale stále jsou běžná, zejména ve starších základech kódu. V moderním jazyce C++ důrazně doporučujeme používat std::vector pole ve stylu jazyka C nebo std::array místo polí popsaných v této části. Oba tyto standardní typy knihoven ukládají své prvky jako souvislý blok paměti. Poskytují však větší bezpečnost typů a podporují iterátory, které jsou zaručeny, že odkazují na platné umístění v rámci sekvence. Další informace najdete v tématu Kontejnery.
Deklarace zásobníku
V deklaraci pole C++ je velikost pole zadána za názvem proměnné, nikoli za názvem typu jako v některých jiných jazycích. Následující příklad deklaruje pole 1 000 dvojitých hodnot, které mají být přiděleny v zásobníku. Počet prvků musí být zadán jako celočíselná literál nebo jinak jako konstantní výraz. Je to proto, že kompilátor musí vědět, kolik prostoru zásobníku se má přidělit; Nemůže použít hodnotu vypočítanou za běhu. Každému prvku v poli je přiřazena výchozí hodnota 0. Pokud nepřiřazujete výchozí hodnotu, každý prvek zpočátku obsahuje jakékoli náhodné hodnoty v tomto umístění paměti.
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] << " ";
}
Prvním prvkem v poli je nula. Posledním prvkem je element (n-1), kde n je počet prvků, které pole může obsahovat. Počet prvků v deklaraci musí být celočíselný typ a musí být větší než 0. Je vaší zodpovědností zajistit, aby program nikdy nepředá hodnotu operátoru dolního indexu, který je větší než (size - 1).
Matice s nulovou velikostí je legální pouze v případech, kdy je pole posledním polem struct v poli nebo union když jsou povolená rozšíření Microsoftu (/Za nebo /permissive- není nastavená).
Pole založená na zásobníku jsou rychlejší alokovat a přistupovat k polím založeným na haldě. Prostor zásobníku je však omezený. Počet prvků pole nemůže být tak velký, že využívá příliš mnoho paměti zásobníku. Kolik je příliš velké, závisí na vašem programu. Pomocí nástrojů pro profilaci můžete určit, jestli je pole příliš velké.
Deklarace haldy
Můžete vyžadovat pole, které je pro přidělení zásobníku příliš velké nebo jejíž velikost není v době kompilace známá. Toto pole je možné přidělit na haldě pomocí výrazu new[] . Operátor vrátí ukazatel na první prvek. Operátor dolního indexu funguje na proměnné ukazatele stejným způsobem jako u pole založeného na zásobníku. K přesunutí ukazatele na libovolné prvky v poli můžete také použít aritmetický ukazatel. Je vaší zodpovědností zajistit, aby:
- vždy zachováte kopii původní adresy ukazatele, abyste mohli odstranit paměť, když už pole nepotřebujete.
- nezvýšíte ani nezvýšíte adresu ukazatele za hranice pole.
Následující příklad ukazuje, jak definovat pole v haldě za běhu. Ukazuje, jak získat přístup k prvkům pole pomocí operátoru dolního indexu a pomocí aritmetické metody ukazatele:
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);
}
Inicializace polí
Pole můžete inicializovat ve smyčce, jeden prvek najednou nebo v jednom příkazu. Obsah následujících dvou polí je shodný:
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 };
Předávání polí funkcím
Když je pole předáno funkci, předává se jako ukazatel na první prvek bez ohledu na to, jestli se jedná o pole založené na zásobníku nebo haldě. Ukazatel neobsahuje žádné jiné informace o velikosti nebo typu. Toto chování se nazývá rozklad ukazatele. Když funkci předáte matici, musíte vždy zadat počet prvků v samostatném parametru. Toto chování také znamená, že prvky pole nejsou zkopírovány, když se pole předá funkci. Pokud chcete funkci zabránit v úpravě prvků, zadejte parametr jako ukazatel na const elementy.
Následující příklad ukazuje funkci, která přijímá pole a délku. Ukazatel odkazuje na původní pole, nikoli kopii. Vzhledem k tomu, že parametr není const, může funkce upravovat prvky pole.
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]
}
}
Deklarujte a definujte parametr p pole tak, aby const byl jen pro čtení v rámci bloku funkce:
void process(const double *p, const size_t len);
Stejnou funkci lze deklarovat také těmito způsoby beze změny chování. Pole se stále předává jako ukazatel na první prvek:
// 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);
Multidimenzionální pole
Matice vytvořené z jiných polí jsou multidimenzionální pole. Tato multidimenzionální pole jsou určena umístěním více závorkových konstantních výrazů v posloupnosti. Představte si například tuto deklaraci:
int i2[5][7];
Určuje pole typu int, koncepčně uspořádané do dvourozměrné matice pěti řádků a sedmi sloupců, jak je znázorněno na následujícím obrázku:
Obrázek je mřížka 7 buněk na šířku a 5 buněk s výškou. Každá buňka obsahuje index buňky. První index buňky je označený jako 0,0. Další buňka v daném řádku je 0,1 a tak dále na poslední buňku v daném řádku, která je 0,6. Další řádek začíná indexem 1,0. Buňka za indexem 1,1. Poslední buňka v daném řádku je 1,6. Tento vzor se opakuje až do posledního řádku, který začíná indexem 4,0. Poslední buňka v posledním řádku má index 4,6.
Můžete deklarovat multidimenzionální pole, která mají seznam inicializátorů (jak je popsáno v inicializátorech). V těchto deklaracích je možné vynechat konstantní výraz, který určuje hranice první dimenze. Příklad:
// 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 }
};
Předchozí deklarace definuje pole, které je tři řádky podle čtyř sloupců. Řádky představují továrny a sloupce představují trhy, do kterých se továrny dodávají. Hodnoty jsou náklady na dopravu z továren na trhy. První dimenze pole je vynecháná, ale kompilátor ji vyplní prozkoumáním inicializátoru.
Použití operátoru nepřímých matic (*) u ndimenzionálního typu pole poskytuje n-1 dimenzionální pole. Pokud n je 1, vynese se skalární (nebo maticový prvek).
Pole jazyka C++ jsou uložena podle pořadí hlavního řádku. Pořadím hlavního řádku se rozumí, že se nejrychlejší dolní index liší od posledního.
Příklad
Specifikace hranic pro první dimenzi multidimenzionálního pole můžete také vynechat v deklaracích funkcí, jak je znázorněno zde:
// 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
Funkce FindMinToMkt je napsaná tak, že přidání nových továren nevyžaduje žádné změny kódu, pouze rekompilace.
Inicializace polí
Pole objektů, které mají konstruktor třídy jsou inicializovány konstruktorem. Pokud je v seznamu inicializátoru méně položek než elementů v poli, použije se výchozí konstruktor pro zbývající prvky. Pokud není definován žádný výchozí konstruktor pro třídu, musí být seznam inicializátor dokončen, to znamená, že musí existovat jeden inicializátor pro každý prvek pole.
Vezměte v úvahu třídu Point definující dva konstruktory:
// 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()
{
}
První prvek pole aPoint je vytvořen pomocí konstruktoru Point( int, int ). Zbývající dva prvky jsou vytvořeny výchozím konstruktorem.
Pole statických členů (bez ohledu na to, zda const je možné) inicializovat v jejich definicích (mimo deklaraci třídy). Příklad:
// 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()
{
}
Přístup k prvkům pole
K jednotlivým prvkům pole můžete přistupovat pomocí operátoru dolního indexu pole ([ ]). Pokud použijete název jednorozměrného pole bez dolního indexu, vyhodnotí se jako ukazatel na první prvek pole.
// 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.
}
Při použití multidimenzionálních polí můžete ve výrazech použít různé kombinace.
// 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.
}
V předchozím kódu multi je trojrozměrné pole typu double. Ukazatel p2multi odkazuje na pole typu double 3. V tomto příkladu se pole používá s jedním, dvěma a třemi dolními indexy. I když je běžnější zadat všechny dolní indexy, jako v cout příkazu, někdy je užitečné vybrat konkrétní podmnožinu prvků pole, jak je znázorněno v příkazech, které následují cout.
Přetížení operátoru dolního indexu
Stejně jako ostatní operátory může uživatel předefinovat operátor dolního indexu ([]). Výchozí chování operátoru indexu, pokud není přetížen, je kombinování názvu pole a indexu pomocí následující metody:
*((array_name) + (subscript))
Stejně jako u všech doplňků, které zahrnují typy ukazatelů, se škálování provádí automaticky, aby se upravila velikost typu. Výsledná hodnota není n bajtů z původu array_name; místo toho je nth prvek pole. Další informace o tomto převodu naleznete v tématu Operátory sčítání.
Pro vícerozměrná pole je adresa odvozena podobně následujícím způsobem:
((array_name) + (subscript1 * max2 * max3 * ... * maxn) + (subscript2 * max3 * ... * maxn) + ... + subscriptn))
Pole ve výrazech
Když se identifikátor typu pole zobrazí ve výrazu jiném než sizeof, adresa (&) nebo inicializace odkazu, převede se na ukazatel na první prvek pole. Příklad:
char szError1[] = "Error: Disk drive not ready.";
char *psz = szError1;
Ukazatel psz odkazuje na první prvek pole szError1. Pole, na rozdíl od ukazatelů, nejsou upravitelné l-hodnoty. Proto je následující přiřazení neplatné:
szError1 = psz;