Массивы указателей с неопределенным размером
От: unz0r  
Дата: 07.11.07 22:09
Оценка: :)
double **a;

// Выделили память
a = (double **)malloc(N*sizeof(double *));
for (int i = 0; i < N; i++) a[i] = (double *)malloc(M*sizeof(double));

// Заполнили массив какими-нибудь значениями
...

// Работаем с ним
WorkWithArray(a);

void WorkWithArray(double **a) {
 fprintf(h, "%lf", a[1][2]);
}


Вопрос: откуда компилятор знает где брать a[1][2], ведь массив выделен динамически? Неужели он рюхает что в массиве N столбцов?


double **a;

fprintf(h, "%lf", aa[1][2]);


Почему вообще компилируется такой код? К какому элементу будет идти обращение, если размер строки нигде не определен?


После всех этих вопросов понял что я совсем дурак и полез в КР.
Там пишут: Если двумерный массив передается функции в качестве аргумента, то объявление соответствующего ему параметра должно содержать количество столбцов ... в качестве примера дают
f(int daytab[][13]) { ... }


Иттить, а как же тогда работает WorkWithArray(double **a) ?
Re: Массивы указателей с неопределенным размером
От: Erop Россия  
Дата: 07.11.07 22:49
Оценка: 3 (1)
Здравствуйте, unz0r, Вы писали:

U>
double **a;

U>fprintf(h, "%lf", aa[1][2]);

U>Почему вообще компилируется такой код? К какому элементу будет идти обращение, если размер строки нигде не определен?

Да просто тут всё. Это не массив массивов, как в случае
double v[N][M];
а массив указателей.

Для начала стоит разобраться с
double vv[N];
double *a = v;
Понимаешь ли ты в чём разница между v и a? И в чём между v[5] и a[5]?
Предположим, чо понимаешь. Тогда, наверное, легко поймёшь и двумерный случай.
double vv[N][M];
double **a;

В одном случае (когда массив массивов) vv[1] имеет тип double[M], а во втором случае (когда указатель на указатель) aa[1] имеет тип double*.

Короче говоря, в случае двумерного массива мы указатель на строку вычисляем, а в случае двойного указателя, мы указатели на строки храним. Не так компактно, конечно, зато быстро и можно выделять динамически
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Массивы указателей с неопределенным размером
От: unz0r  
Дата: 07.11.07 23:39
Оценка:
Здравствуйте, Erop, Вы писали:

E>Короче говоря, в случае двумерного массива мы указатель на строку вычисляем, а в случае двойного указателя, мы указатели на строки храним. Не так компактно, конечно, зато быстро и можно выделять динамически


Все понял. Спасибо огромное!
Re: Массивы указателей с неопределенным размером
От: Don Reba Канада https://stackoverflow.com/users/49329/don-reba
Дата: 07.11.07 23:56
Оценка:
int main()
{
    int v[2][2] = { 2, 3, 5, 7};
    std::cout << 0[1[v]] << '\n';
}

Дело в том, что оператор [] всего лишь выполняет простую операцию. x[y] то же самое, что и *(x+y)
Ce n'est que pour vous dire ce que je vous dis.
Re: Массивы указателей с неопределенным размером
От: Alexey Borodin alexey-borodin@narod.ru
Дата: 08.11.07 09:52
Оценка:
Здравствуйте, unz0r, Вы писали:

U>void WorkWithArray(double **a) {

U> fprintf(h, "%lf", a[1][2]);
U>}
U>[/ccode]

U>Вопрос: откуда компилятор знает где брать a[1][2], ведь массив выделен динамически? Неужели он рюхает что в массиве N столбцов?


В С++ нет двойных массивов. Есть только одинарные и вложенные, как здесь.
a[1][2] — это обращение к третьему подмассиву второго массива. В памяти эта конструкция представляет одномерный массив указателей. Плюс ещё n одномерных массивов, на которые эти указатели ссылаются.

a[1][2] —
a — массив указателей.
Поэтому a[1] — доступ к элементу этого массива, там записан адрес другого массива. Т.е. a[1] — это всего-лишь указатель (в данном случае на др. массив).
(a[1])[2] — доступ к элементу вложенного массива. Компилятор ничего не знает о его размере, он просто сдвигает указатель на 2 элемента вперёд.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.