Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Uma matriz é uma sequência de objetos do mesmo tipo que ocupam uma área contígua de memória. As matrizes tradicionais no estilo C são a fonte de muitos bugs, mas ainda são comuns, especialmente em bases de código mais antigas. No C++ moderno, é altamente recomendável usar std::vector ou std::array em vez de matrizes no estilo C descritas nesta seção. Ambos os tipos de biblioteca padrão armazenam seus elementos como um bloco contíguo de memória. No entanto, eles fornecem maior segurança de tipos e suportam iteradores que garantidamente apontam para um local válido dentro da sequência. Para obter mais informações, consulte Contêineres.
Declarações de pilha
Em uma declaração de matriz C++, o tamanho da matriz é especificado após o nome da variável, não após o nome do tipo, como em alguns outros idiomas. O exemplo a seguir declara uma matriz de 1000 duplos a serem alocados na pilha. O número de elementos deve ser fornecido como um literal inteiro ou então como uma expressão constante. Uma vez que o compilador precisa saber quanto espaço de pilha alocar, ele não pode usar um valor calculado em tempo de execução. A cada elemento na matriz é atribuído um valor padrão de 0. Se você não atribuir um valor padrão, cada elemento inicialmente conterá quaisquer valores aleatórios que estejam nesse local de memória.
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] << " ";
}
O primeiro elemento do array é o elemento zero. O último elemento é o elemento (n-1), onde n é o número de elementos que a matriz pode conter. O número de elementos da declaração deve ser de tipo integral e superior a 0. É sua responsabilidade garantir que seu programa nunca passe um valor para o operador subscrito que seja maior que (size - 1).
Uma matriz de tamanho zero é legal somente quando a matriz é o último campo em um struct ou union e quando as extensões da Microsoft estão habilitadas (/Za ou /permissive- não estão definidas).
As matrizes baseadas em pilha são mais rápidas de alocar e acessar do que as matrizes baseadas em heap. No entanto, o espaço da pilha é limitado. O número de elementos da matriz não pode ser tão grande a ponto de consumir demasiada memória de pilha. Quanto é demais depende do seu programa. Você pode usar ferramentas de criação de perfil para determinar se uma matriz é muito grande.
Declarações de heap
Você pode precisar de uma matriz que seja muito grande para alocar na pilha ou cujo tamanho não seja conhecido no momento da compilação. É possível alocar essa matriz no heap usando uma new[] expressão. O operador retorna um ponteiro para o primeiro elemento. O operador subscrito funciona na variável de ponteiro da mesma forma que funciona em uma matriz baseada em pilha. Você também pode usar a aritmética do ponteiro para mover o ponteiro para quaisquer elementos arbitrários na matriz. É da sua responsabilidade garantir que:
- Você sempre mantém uma cópia do endereço de ponteiro original para que possa excluir a memória quando não precisar mais da matriz.
- você não incrementa ou diminui o endereço do ponteiro além dos limites da matriz.
O exemplo seguinte mostra como definir um array no heap durante a execução. Mostra como aceder aos elementos da matriz usando o operador de índice e usando a aritmética de ponteiros:
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);
}
Inicializando matrizes
Você pode inicializar uma matriz em um loop, um elemento de cada vez ou em uma única instrução. O conteúdo das duas matrizes a seguir é idêntico:
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 };
Passando matrizes para funções
Quando uma matriz é passada para uma função, ela é passada como um ponteiro para o primeiro elemento, seja uma matriz baseada em pilha ou heap. O ponteiro não contém nenhuma outra informação de tamanho ou tipo. Esse comportamento é chamado de decaimento de ponteiro. Ao passar uma matriz para uma função, você sempre deve especificar o número de elementos em um parâmetro separado. Esse comportamento também implica que os elementos da matriz não são copiados quando a matriz é passada para uma função. Para impedir que a função modifique os elementos, especifique o parâmetro como um ponteiro para const os elementos.
O exemplo a seguir mostra uma função que aceita uma matriz e um comprimento. O ponteiro aponta para a matriz original, não para uma cópia. Como o parâmetro não é const, a função pode modificar os elementos da matriz.
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]
}
}
Declare e defina o parâmetro p do array como const de forma a torná-lo somente leitura dentro do bloco de função:
void process(const double *p, const size_t len);
A mesma função também pode ser declarada dessas maneiras, sem mudança de comportamento. A matriz ainda é passada como um ponteiro para o primeiro elemento:
// 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);
Matrizes multidimensionais
Matrizes construídas a partir de outras matrizes são matrizes multidimensionais. Essas matrizes multidimensionais são especificadas colocando várias expressões constantes entre colchetes em sequência. Por exemplo, considere esta declaração:
int i2[5][7];
Especifica uma matriz de tipo int, conceitualmente organizada em uma matriz bidimensional de cinco linhas e sete colunas, como mostra a figura a seguir:
A imagem é uma grade de 7 células de largura e 5 células de altura. Cada célula contém o índice da célula. O primeiro índice de células é rotulado como 0,0. A célula seguinte nessa linha é 0,1 e assim por diante até à última célula dessa linha, que é 0,6. A próxima linha começa com o índice 1,0. A célula depois disso tem um índice de 1,1. A última célula dessa linha é 1,6. Este padrão repete-se até à última linha, que começa com o índice 4,0. A última célula da última linha tem um índice de 4,6.
Você pode declarar matrizes multidimensionais que tenham uma lista de inicializadores (conforme descrito em Inicializadores). Nessas declarações, a expressão constante que especifica os limites para a primeira dimensão pode ser omitida. Por exemplo:
// 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 }
};
A declaração anterior define uma matriz que é de três linhas por quatro colunas. As linhas representam fábricas e as colunas representam mercados para os quais as fábricas enviam. Os valores são os custos de transporte das fábricas para os mercados. A primeira dimensão da matriz é deixada de fora, mas o compilador a preenche examinando o inicializador.
O uso do operador indirection (*) em um tipo de matriz n-dimensional produz uma matriz dimensional n-1. Se n for 1, um elemento escalar (ou de matriz) será produzido.
As matrizes C++ são armazenadas em ordem de linha principal. A ordem por linha indica que o último subscrito varia mais rapidamente.
Exemplo
Você também pode omitir a especificação de limites para a primeira dimensão de uma matriz multidimensional em declarações de função, conforme mostrado aqui:
// 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 função FindMinToMkt é escrita de tal forma que adicionar novas fábricas não requer nenhuma alteração de código, apenas uma recompilação.
Inicializando matrizes
Matrizes de objetos que têm um construtor de classe são inicializadas pelo construtor. Quando há menos itens na lista de inicializadores do que elementos na matriz, o construtor padrão é usado para os elementos restantes. Se nenhum construtor padrão for definido para a classe, a lista de inicializadores deverá estar completa, ou seja, deve haver um inicializador para cada elemento na matriz.
Considere a Point classe que define dois construtores:
// 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()
{
}
O primeiro elemento de aPoint é construído usando o construtor Point( int, int ), os dois elementos restantes são construídos usando o construtor padrão.
Arrays de membros estáticos (se possuem const ou não) podem ser inicializadas nas suas definições (fora da declaração de classe). Por exemplo:
// 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()
{
}
Acessando elementos de matriz
Pode aceder a cada elemento de uma matriz usando o operador de subscrito de matriz ([ ]). Se utilizares o nome de um array unidimensional sem um subíndice, ele será interpretado como um ponteiro para o primeiro elemento do array.
// 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.
}
Ao usar matrizes multidimensionais, você pode usar várias combinações em expressões.
// 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.
}
No código anterior, multi é uma matriz tridimensional do tipo double. O p2multi ponteiro aponta para uma matriz do tipo double com dimensão três. Neste exemplo, a matriz é utilizada com um, dois e três índices. Embora seja mais comum especificar todos os subscritos, como na instrução cout, por vezes, é útil selecionar um subconjunto específico de elementos de uma matriz, conforme mostrado nas instruções que se seguem a cout.
Sobrecarregando o operador de subscrito
Como acontece com outros operadores, o operador subscrito ([]) pode ser redefinido pelo utilizador. O comportamento padrão do operador de índice, se não estiver sobrecarregado, é combinar o nome da matriz e o índice usando o seguinte método:
*((array_name) + (subscript))
Como em toda adição que envolve tipos de ponteiro, o dimensionamento é feito automaticamente para ajustar o tamanho do tipo. O valor resultante não é n bytes da origem de array_name; em vez disso, é o nésimo elemento da matriz. Para obter mais informações sobre essa conversão, consulte Operadores aditivos.
Da mesma forma, para matrizes multidimensionais, o endereço é derivado usando o seguinte método:
((array_name) + (subscript1 * max2 * max3 * ... * maxn) + (subscript2 * max3 * ... * maxn) + ... + subscriptn))
Matrizes em expressões
Quando um identificador de um tipo de array aparece em uma expressão que não seja sizeof, address-of (&), ou inicialização de uma referência, ele é convertido em um ponteiro para o primeiro elemento do array. Por exemplo:
char szError1[] = "Error: Disk drive not ready.";
char *psz = szError1;
O ponteiro psz aponta para o primeiro elemento da matriz szError1. As matrizes, ao contrário dos ponteiros, não são valores L modificáveis. É por isso que a seguinte atribuição é ilegal:
szError1 = psz;