Привет!
Я недавно начал изучать C. Появились некоторые вопросы...
Каким образом правильно передавать двумерные(или 3-мерные) массивы в функции?
И как осуществлять доступ к отдельным элементам?
Почему для простого указателя int *p нельзя написать p[...][...], а требуется указывать тип int **? Ведь двумерные массивы (M x N) на самом деле располагаются в непрерывном блоке, как и простой вектор длины M*N?
Этот код не работает:
#include <stdio.h>
int arr[3][3] = {
1, 2, 3,
4, 5, 6,
7, 8, 9,
};
void fn(int **array, int m, int n)
{
int k, j, *p;
p = array;
for(k = 0; k < m; k++)
{
for(j = 0; j < n; j++)
printf("%i ", array[k][j]);
putchar('\n');
}
/*for(k = 0; k < m; k++)
{
for(j = 0; j < n; j++)
printf("%i ", p++);
putchar('\n');
}*/
}
int main()
{
arr[0][1] = 9;
fn(arr, 3, 3);
return 0;
}
Дело в том, что для массивов оператор [] имеет тот же самый смысл, что и *.
То есть array[index] можно записать как *(array + index).
Именно по этой причине записи array[index] и index[array] эквиваленты.
Когда [] применяется для двухмерных массивов, то его результат — указатель на строку/столбец.
Таким образом [][] — **, а двойное разъименовывание для простого указателя не имеет смысла.
Re[2]: массивы в C
От:
Аноним
Дата:
09.09.06 14:13
Оценка:
Здравствуйте, kirill_kl, Вы писали:
_>Дело в том, что для массивов оператор [] имеет тот же самый смысл, что и *.
_>То есть array[index] можно записать как *(array + index). _>Именно по этой причине записи array[index] и index[array] эквиваленты.
_>Когда [] применяется для двухмерных массивов, то его результат — указатель на строку/столбец.
_>Таким образом [][] — **, а двойное разъименовывание для простого указателя не имеет смысла.
Ну а физически двухмерный массив ничем не отличается от одномерного массива того же размера. Или я не прав в чем-то? Другое дело — массив указателей, указывающих на другие области памяти.
Ладно, предположим в теории все понятно, но как реализовать передачу матрицы M x N в функцию, допустим, выводящую ее в stdout при помощи двойного разыменования [][]??? Мне такое не удалось. Плз, напишите код, тогда все вопросы отпадут.
Здравствуйте, Аноним, Вы писали:
А>Ладно, предположим в теории все понятно, но как реализовать передачу матрицы M x N в функцию, допустим, выводящую ее в stdout при помощи двойного разыменования [][]??? Мне такое не удалось. Плз, напишите код, тогда все вопросы отпадут.
Может, вот это поможет?
Было бы здорово, если бы можно было создать двухмерный динамический массив произвольных размеров, например:
float *r = new float[m][n];
Однако такая запись является ошибкой — вычисляемым может быть только первое, самое левое измерение, остальные должны быть заданы константами. Обычно двухмерные динамические массивы применяются при реализации матричной арифметики. И такое ограничение существенно затрудняет написание универсальных функций для работы с матрицами произвольных размеров. Эту проблему решают по-разному. Наиболее современное решение — это шаблоны, в которых размеры матриц задаются как параметры шаблона. Однако в этом случае объект-матрица будет иметь большой размер. Поэтому лучше все-таки использовать динамическую память. Сначала создается динамический массив указателей на массивы (строки матрицы), а затем каждый указатель инициализируется динамическим массивом для чисел. Таким образом, наш «главный» указатель является указателем на указатели:
int n; // количество строк матрицыint m; // количество столбцов матрицыfloat **M = new float *[n]; // массив указателей на строки матрицыfor(int i = 0; i < n; ++i)
M[i] = new float[m]; // строки матрицы
Работу по резервированию памяти может выполнять конструктор класса-матрицы. Тогда деструктор должен память возвращать. И это как раз тот случай, когда деструктор нужно реализовать явно.
Возврат памяти тоже осуществляется «постепенно»: сначала возвращаются массивы для чисел, а затем — массив указателей:
for (i=0; i<n; i++) delete[] M[i];
delete[]M;
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[4]: массивы в C
От:
Аноним
Дата:
09.09.06 15:02
Оценка:
Здравствуйте, LaptevVV, Вы писали:
LVV>Здравствуйте, Аноним, Вы писали:
А>>Ладно, предположим в теории все понятно, но как реализовать передачу матрицы M x N в функцию, допустим, выводящую ее в stdout при помощи двойного разыменования [][]??? Мне такое не удалось. Плз, напишите код, тогда все вопросы отпадут.
LVV>Может, вот это поможет?
Ну я же сказал:
Другое дело — массив указателей, указывающих на другие области памяти.
Такой вариант с malloc у меня работал. А как насчет статических двухмерных массивов??? Их гораздо проще и нагляднее заполнять данными. Напишите небольшой код, где в функцию передается матрица M x N, а затем с ней что-то творится при помощи [...][...]. Это не какая-то ведь реальная задача, а просто учебный пример.
Что-то типа такого:
int arr[3][3] = {
1, 2, 3,
4, 5, 6,
7, 8, 9,
};
void fn(MATRIX array, M m, N n)
{
for(k = 0; k < m; k++)
{
for(j = 0; j < n; j++)
printf("%i ", array[k][j]);
putchar('\n');
}
}
int main()
{
fn(arr, 3, 3);
return 0;
}
Либо изменить сигнатуру так, чтобы компилятор понял Ваши намерения (n становится лишним так как количество элементом в строке уже зафиксировано при декларации):
void fn(int array[][3], int m /*, int n */)
Либо действительно работать с линейным представлением массива, опять же, несколько меняя сигнатуру:
void fn(int *array, int m, int n)
{
int k, j, *p;
p = array;
for(k = 0; k < m; k++)
{
for(j = 0; j < n; j++)
printf("%i ", array[k*n + j]);
putchar('\n');
}
/*for(k = 0; k < m; k++)
{
for(j = 0; j < n; j++)
printf("%i ", p++);
putchar('\n');
}*/
}
...
fn(&arr[0][0], 3, 3);
Здравствуйте, Аноним, Вы писали:
А>Привет! А>Я недавно начал изучать C. Появились некоторые вопросы... А>Каким образом правильно передавать двумерные(или 3-мерные) массивы в функции? А>И как осуществлять доступ к отдельным элементам?
А>Почему для простого указателя int *p нельзя написать p[...][...], а требуется указывать тип int **? Ведь двумерные массивы (M x N) на самом деле располагаются в непрерывном блоке, как и простой вектор длины M*N?
Двумерные массивы да. Но p[][] — это двумерный "ступенчатый" массив.
Проще говоря.
int A[2][3] = {{1, 2, 3}, {4, 5, 6}}; // числа в памяти так и записаны
// с помощью p можно писать в одномерный массив
// {1, 2, 3, 4, 5, 6}int * p = &A[0];
p[0] = 100; // изменяем массив на {100, 2, 3, 4, 5, 6}
/// Дальше так:int **D = (int **)p;
// Компилятор воспримет обращение к D[0]
// как к указателю на одномерный массив
// Мы получаем указатель на одномерный массив.
// Если бы у нас вместо 100 был бы указатель, то всё было бы int * p1 = D[0]; классно
//----------------------
// Т.е. надо сделать так:
// создаём два несвязанных друг с другом массиваint A1[] = {1, 2, 3};
int A2[] = {4, 5, 6};
// Создаём массив, в котором есть указатели на массивыint * A[2] = {&A1[0], &A2[0]};
int ** p = &A[0];
// Например, увидев обращение к p[1][0] программа должна считать первый элемент массива A.
// Этот элемент - указатель на массив A2
// Дальше программа обращается к первому (нулевому, то есть) элементу массива A2
// Понятно в чём отличие?
Нужно понять, что указатель — это целочисленная переменная, содержащая адрес. При обращении к int ** p мы получаем указатель, т.е. p[i] даст нам некоторый указатель из одномерного массива с базовым адресом p, а дальше идёт обращение уже к этому указателю, т.е. p[i][j] эквивалентно int * r = p[i]; чего-то там = r[j];
Потом делаешь class T_MATRIX : protected T_ARRAY_STATIC и перегружаешь операторы =*(T_MATRIX), т.к. перемножение матриц в отличии от перемножения массивов подчиняется другим правилам, и т.д.
Если не пугает перспектива напиcания кучи кода для классов, то вперёд Ж))
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
" Аноним " <0@users.rsdn.ru> wrote in message news:2101769@news.rsdn.ru... > Привет! > Я недавно начал изучать C. Появились некоторые вопросы... > Каким образом правильно передавать двумерные(или 3-мерные) массивы в функции? > И как осуществлять доступ к отдельным элементам? > > Почему для простого указателя int *p нельзя написать p[...][...], а требуется указывать тип int **? Ведь двумерные массивы (M x N) на самом деле располагаются в непрерывном блоке, как и простой вектор длины M*N? > > ><skipped>
Следует помнить, что приведенные три варианта идентичны с точки зрения компилятора, и попытка определить любые два из них одновременно приведет к ошибке компиляции.
Posted via RSDN NNTP Server 2.0
--
Справедливость выше закона. А человечность выше справедливости.