Попробуем поработать с матрицами. Матрицу можно представить в виде одномерного массива:
#include <iostream>
int main() {
const int rows = 4;
const int cols = 5;
int A[rows*cols];
// Тогда к элементам можно обращаться: A_ij = A[ i*cols + j ]
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
A[i*cols + j] = i + j + 1;
}
}
std::cout << "A = " ;
for (int i = 0; i < rows * cols; ++i) {
std::cout << A[i] << " ";
}
std::cout << std::endl;
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
A[i*cols + j] = i + j + 1;
}
}
return 0;
}
Но гораздо удобнее работать сразу с двумерным массивом:
int M[rows][cols];
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
M[i][j] = i + j + 1;
}
}
std::cout << "M = " << std::endl;
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
std::cout << M[i][j] << " ";
}
std::cout << std::endl;
}
Есть несколько способов инициализации массива:
int M1[3][4] = {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}};
int M2[3][4] = {{1,2}, {5,6,7}, {9}}; // {{1,2,0,0}, {5,6,7,0}, {9,0,0,0}}
int M2[3][4] = {1,2,3,4,5,6}; // {{1,2,3,4}, {5,6,0,0}, {0,0,0,0}}
int M4[][4] = {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}};
int M5[][4] = {{1,2}, {5,6,7}, {9}}; // {{1,2,0,0}, {5,6,7,0}, {9,0,0,0}}
int M6[][4] = {1,2,3,4,5,6}; // {{1,2,3,4}, {5,6,0,0}, {0,0,0,0}}
// Рассмотрим также варианты, которые выдадут ошибки:
int M7[3][] = {1,2,3,4,5,6};
int M8[3][] = {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}};
Кроме одномерных и двумерных массивов, мы можем использовать массивы и других размерностей.
// Пример трехмерного массива
int IMG[3][rows][cols];
for (int k = 0; k < 3; ++k) {
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
IMG[k][i][j] = (k+1)*100 + (i+1)(j+1);
}
}
}
std::cout << "IMG = " << std::endl;
for (int k = 0; k < 3; ++k) {
std::cout << "page: " << k << std::endl;
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
std::cout << IMG[k][i][j] << " ";
}
std::cout << std::endl;
}
}
Правила инициализации трехмерного массива:
int B1[2][3][4] = {{{1,2,3,4}, {1,2,3,4}, {1,2,3,4}}, {{5,6,7,8}, {5,6,7,8}, {5,6,7,8}}};
// Можно пропустить одну из размерностей.
int B2[][3][4] = {{{1,2,3,4}, {1,2,3,4}, {1,2,3,4}}, {{5,6,7,8}, {5,6,7,8}, {5,6,7,8}}};
int B3[][3][4] = {1,2,3,4,1,2,3,4,1,2,3,4,5,6,7,8,5,6,7,8,5,6,7,8};
Уделим некоторое время на тип данных string.
#include <iostream>
#include <string>
int main() {
std::string str1 = "Hello"; // string хранит не только строку, но и информацию о ней:
// размер, количество занятой памяти т.д.
std::string str2("world!");
std::cout << str1 << " " << str2 << std::endl;
std::string str3 = str1 + " " + str2; // мы можем складывать строки (конкатенация).
std::cout << str3 << std::endl;
return 0;
}
Мы можем работать со строкой как с массивом символов:
for (int i = 0; i < str3.lehgth(); ++i) {
std::cout << char(str3[i] + 1);
}
// s.length() - это размер строки, количество элементов в ней.
// Можно использовать также s.size().
С помощью sizeof() мы можем узнать размер переменной, но что если мы хотим узнать, в какой ячейке она находится. Для этого используются указатели. Указатель — это по сути адрес переменной. Он указывает на ячейку памяти, с которой начинается переменная.
#include <iostream>
int main() {
double x = 234567891234.5;
std::cout << "x = " << x << std::endl;
std::cout << "sizeof(x) = " << sizeof(x) << std::endl;
double *px; // Объявление указателя на переменные типа double.
// Для этого добавляем символ *
px = &x; // Присваиваем указателю адрес x. Для взятия адреса используется символ &.
std::cout << " px = " << px << std::endl; // Увидим номер ячейки, в которой хранится x.
std::cout << " *px = " << *px << std::endl; // * - операция разыменования указателя.
// Выведется значение, которой хранится в указанной ячейке, т.е. значение x.
std::cout << " sizeof(px) = " << sizeof(px) << std::endl;
// Для указателей всегда есть фиксированный размер, зависящи операционной системы.
double y = 4.56;
px = &y;
// Теперь выведется адрес ячейки, где хранится y, и его значение.
std::cout << " px = " << px << std::endl;
std::cout << " *px = " << *px << std::endl;
// Попробуем изменить значение, которое хранится в ячейке.
*px = 0.0;
std::cout << " px = " << px << std::endl;
std::cout << " *px = " << *px << std::endl;
// Теперь значение y тоже равно 0.
return 0;
}
Мы можем также создавать указатели на указатели, а не только на переменные. Тогда нужно использовать несколько символов *.
double** pp;
pp = &px;
std::cout << " pp = " << pp << std::endl;
std::cout << " *pp = " << *pp << std::endl; // выведет значение px, т.е. адрес y.
std::cout << " **pp = " << **pp << std::endl; // выведет значение y.
**pp = 2.3;
std::cout << " sizeof(pp) = " << sizeof(pp) << std::endl;
Для указателей тоже работает преобразование типов:
int *p;
p = (int*) &x;