[С++] объявить указатель на двухмерный массив?
![](/images/graemlins/crazy.gif)
Когда вы все наконец забудете про сущестование многомерных массивов?
Риччи и Кернигана убить за них мало. Даже оператор goto не такое зло.
а в чем подстава многомерных массивов?
typedef TMyArray* PMyArray;
PMyArray parray;
спасибо
а в чем подстава многомерных массивов?присоединяюсь к вопросу и ещё попрошу подсказать какую нибудь более удобную замену
а в чем подстава многомерных массивов?в том что они нафик не нужны (не добавляют функциональности)
в том, что читабельность от них только ухудшается (надо долго разбираться как там эти элементы расположены в памяти, и не путать индексы)
И самое главное - они портят логику C-шных массивов, если бы не существование многомерных массивов, можно было бы считать массив просто константным указателем, указывающим на определенное количество последовательных элементов, занимающих статически выделенную память, а так это якобы какой-то отдельный тип, который тем не менее не аналогичен другим типам (например: объект этого типа не передается в функцию по значению как объекты всех остальных типов при аналогичном объявлении функции, и так же мы не можем одному массиву присвоить значение другого оператором =, как для всех остальных типов бред короче.
и ещё попрошу подсказать какую нибудь более удобную заменуочевидно обычный одномерный массив
например двумерный размером M*N: вместо a[j][k] будет a[j*N+k]
Или массив массивов
зачем?
договорись сам с собой - используешь ты индексацию x, y или y, x и всё
> можно было бы считать массив просто константным указателем
что реально полезного дает такое обобщение?
vector<vector<int> > myVector;
sub.cpp:
char str[] = "hello\n";
main.cpp:
#include <iostream>
extern char * str;
int main
{
std::cout<<str<<std::endl;
return 0;
}
kai:~$ g++ -W -Wall -ansi -pedantic main.cpp sub.cpp
kai:~$ ./a.out
Segmentation fault
(C) С. Уэллин
Интересно, почему компилятор не видит противоречия между extern char* и char[]... По идее он должен сказать о неразрешенной (unresolved) ссылке.
Компилятор ниразу не видит их одновременно.
Пардон, неправильно выразился. Не компилятор, а линкер.
ясен пень, что в памяти, отведенной под str, в sub.cpp пишется сама строка, а в main.cpp полагается, что там указатель лежит
зы. array-to-pointer конверсия не просто же так придумана
А пример интересный, я не знал ...
а кто-нть понимает, почему вылетает этот пример?
![](/images/graemlins/smile.gif)
Но ИМХО, так:
В sub.cpp отводится память под строку, при этом конкретно под указатель памяти не отводится. Везде, где ты пытаешься использовать str как указатель, идет преобразования из массива символов в указатель.
В main.cpp предполагается, что str - это переменная, в которой хранится указатель. На самом деле там хранится буква 'h', поэтому получается неправильный указатель, при выводе которого вылетает segmentation fault.
Я так думаю.
![](/images/graemlins/smile.gif)
Только там не 'h', а 'hell' для 32-битной архитектуры
В сущности, чудный каламбурчик насчет hell.
Только там не 'h', а 'hell' для 32-битной архитектурыТочнее, если указатель 32-битный. Конкретное количество байтов и их порядок в общем случае зависит не только от разрядности, но также и других особенностей архитектуры процессора и ОС, да и от компилятора тоже.
ему главное, чтобы по кол-ву байт всё сошлось...
Короче, глобальные статические массивы использовать крайне не рекомендуется. Глобальные переменные, правда, лучше ненамного, но все-таки они не позволяют таким образом переводить ошибки компиляции или компоновки в ошибки выполнения.
Размер тоже неважен. В этом примере он разный, а линкер молчит. Оно и понятно, откуда в main.o взяться информации о размере str ?
Ну потому что в дерективе extern мы указали тип str - указатель на char, так что о размере должен бы догадываться вроде
Просто у тебя переменная в разных единицах компиляции имеет разные типы, только и всего. С функцией в плюсах такое не пройдет, потому что типы аргументов шифруются в имени символа, но в Си - запросто.
Чтобы избежать такой фигни, extern должен быть помещен в заголовочный файл, и включен в оба cpp.
Просто для функций размер заранее не известен, а механизм линковки - общий.
Код не претендует на оптимальность и отсутствие ошибок,
особенно часть про двумерные массивы
int _tmain(int argc, _TCHAR* argv[])
{
double *arr1;
double *arr2;
clock_t t = clock;
for (int i=0; i< C_MAX; i++) {
arr1 = new double [M_MAX*M_MAX];
arr2 = new double [M_MAX*M_MAX];
memcpy(arr1, arr2, M_MAX*M_MAX*sizeof(double;
delete arr1;
delete arr2;
}
std::cout << "First Type. Time -- " << doubleclock - t / CLOCKS_PER_SEC << "s" <<std::endl;
t = clock;
double **darr1;
double **darr2;
for (int i=0; i < C_MAX; i++) {
darr1 = new double * [M_MAX];
darr2 = new double * [M_MAX];
for (int j=0; j < M_MAX; j++) {
darr1[j] = new double [M_MAX];
darr2[j] = new double [M_MAX];
memcpy(darr1[j], darr2[j], M_MAX);
}
delete [] darr1;
delete [] darr2;
}
std::cout << "First Type. Time -- " << doubleclock - t / CLOCKS_PER_SEC << "s" << std::endl;
return 0;
}
Результат
#define M_MAX 1024
#define C_MAX 50
First Type. Time — 1.671s
First Type. Time — 47.032s
//------------------------------
#define M_MAX 10
#define C_MAX 999
First Type. Time — 0.015s
First Type. Time — 0.063s
Однако
#define M_MAX 1000
#define C_MAX 10
First Type. Time — 0.312s
First Type. Time — 0.156s
PS Удалять тоже надо правильно.
![](/images/graemlins/smile.gif)
честно говоря я как раз и хотел, чтобы мне показали как правильно
чтобы мне показали как правильноКак делать правильно зависит от задачи.
![](/images/graemlins/smile.gif)
да, наверно делать это в цикле 999 раз действительно не очень жизненноДа. Особенно если на каждой итерации удалять всё.
![](/images/graemlins/smirk.gif)
double **darr1; double **darr2; for (int i=0; i < C_MAX; i++) { darr1 = new double * [M_MAX]; darr2 = new double * [M_MAX]; for (int j=0; j < M_MAX; j++) { darr1[j] = new double [M_MAX]; darr2[j] = new double [M_MAX]; memcpy(darr1[j], darr2[j], M_MAX); } delete [] darr1; delete [] darr2; }А где же delete [] darr1[i], delete [] darr2[i]?
И кстати, удалять arr1 и arr2 тоже желательно оператором delete [], а не просто delete.
![](/images/graemlins/smile.gif)
Насколько я знаю, фишка между delete и delete[] проявляется в вызове деструкторов для всех уничтожаемых объектов во втором случае. Т.ч. со встроенными типами разница незаметна. Хотя мб я чего-то не помню уже, давно обсуждалось где-то в разделе.
Оставить комментарий
Ventalf
Напомните пожалуйста, как объявить указатель на двойной массив типа ?__int32 replModule[8][16];