Вопросы экзамена по C++ и примерные задачи
Инструкция по установке компилятора C++ и IDE Geany в Windows
Программа курса «Программирование на C++» и список рекомендуемой литературы
Если бы массив был динамическим, то в функцию достаточно было бы передать указатель на указатель. Примерно так:
#include <iostream> #include <cstdlib> #include <ctime> using namespace std; void arrprint(int** arr, int m, int n) { for(int i = 0; i < m; i++) { for(int j = 0; j < n; j++) { cout << arr[i][j] << ' ' << &arr[i][j] << '\t'; } cout << endl; } } int main() { int m=3, n=5; int** p = new int*[m]; for(int i = 0; i < m; i++) { p[i] = new int[n]; for(int j = 0; j < n; j++) { p[i][j] = rand()%10; } } arrprint(p, m, n); for(int i = 0; i < m; i++) delete[] p[i]; delete[] p; }
Обратите внимание на адреса, они будут примерно такими:
1 0x760ff8 7 0x760ffc 4 0x761000 0 0x761004 9 0x761008 4 0x761018 8 0x76101c 8 0x761020 2 0x761024 4 0x761028 5 0x761038 5 0x76103c 1 0x761040 7 0x761044 1 0x761048
Из адресов видно, что каждый одномерный динамический массив (являющийся условной «строкой» двумерного) располагаться в памяти может где угодно. Хотя элементы внутри каждой строки лежат последовательно друг за другом (через 4 байта для типа int).
Создадим теперь двумерный статический массив и посмотрим на его адреса:
#include <iostream> #include <cstdlib> #include <ctime> using namespace std; int main() { const int m=3, n=5; int a[m][n]; for(int i = 0; i < m; i++) { for(int j = 0; j < n; j++) { a[i][j] = rand()%10; cout << a[i][j] << ' ' << &a[i][j] << '\t'; } cout << endl; } }
Адреса будут такими:
1 0x22fed4 7 0x22fed8 4 0x22fedc 0 0x22fee0 9 0x22fee4 4 0x22fee8 8 0x22feec 8 0x22fef0 2 0x22fef4 4 0x22fef8 5 0x22fefc 5 0x22ff00 1 0x22ff04 7 0x22ff08 1 0x22ff0c
Из адресов видно, что «строки» статического двумерного массива в памяти располагаются строго друг за другом. То есть, по сути, двумерный массив размерности m на n в памяти размещается ровно также, как и одномерный массив размерности m*n.
А из этого, в частности, следует, что работать со статическим двумерным массивом мы можем через указатель первого уровня (в данном случае, через int*
).
Значит передать в функцию двумерный статический массив можно, например, так:
#include <iostream> #include <cstdlib> #include <ctime> using namespace std; void arrprint(int* arr, int m, int n) { for(int i = 0; i < m; i++) { for(int j = 0; j < n; j++) { cout << *(arr + i*n + j) << ' '; } cout << endl; } } int main() { int a[3][6] ={ {3,7,8,0,1,4}, {2,9,1,4,7,6}, {5,2,7,6,1,9} }; arrprint(&a[0][0], 3, 6); }
Традиционное допущение «массив есть указатель» справедливо только для одномерного массива, да и то за счёт того, что при выполнении следующего кода происходит автоприведение:
int a[10]; int* p = a;
Но вот следующий пример уже является ошибкой:
int a[7][3]; int** p = a;
Попытавшись его выполнить, получим примерно такое сообщение от отладчика: hello.cpp:8:12: cannot convert int (*)[3] to int** in initialization
.
«Массив массивов» и «указатель на указатель» — это разные сущности. И разница между ними видна, например, на таком коде:
#include <iostream> #include <cstdlib> #include <ctime> using namespace std; int main() { int a[3][6] ={ {3,7,8,0,1,4}, {2,9,1,4,7,6}, {5,2,7,6,1,9} }; int* p = &a[0][0]; int** q = &p; cout << a[0][0] << endl; // 3 cout << q[0][0] << endl; // 3 cout << a[0] << endl; // 0x22fec0 cout << q[0] << endl; // 0x22fec0 cout << a[0][2] << endl; // 8 cout << q[0][2] << endl; // 8 cout << a[1] << endl; // 0x22fec0 cout << q[1] << endl; // 0x22fed8 cout << a[1][2] << endl; // 1 cout << q[1][2] << endl; // 246351 }
Если в рамках задачи функция будет использоваться для обработки массивов с заведомо одинаковой длиной строк, то функцию возможно описать и потом вызывать вот так (пожертвовав её универсальностью, зато получив привычную возможность внутри функции работать не по смещению указателя, а по двум индексам):
#include <iostream> #include <cstdlib> #include <ctime> using namespace std; void arrprint(int arr[][6], int m) { for(int i = 0; i < m; i++) { for(int j = 0; j < 6; j++) { cout << arr[i][j] << ' '; } cout << endl; } } int main() { int a[3][6] ={ {3,7,8,0,1,4}, {2,9,1,4,7,6}, {5,2,7,6,1,9} }; arrprint(a, 3); }