Невозможно выделить память для массива постоянного нулевого размера
В этом примере сначала выделяется память под массив указателей, потом M раз выделяется память под массивы. Во время удаления массива сначала M раз удаляются массивы, а потом удаляется массив указателей. Операции malloc и free затратные. Кроме того, выделение маленьких кусков памяти приводит к фрагментации памяти, так что последующее выделение памяти становится ещё медленнее.
Массив - это непрерывная последовательность байт. Массив не хранит своего размера. Указатель на массив хранит всего лишь адрес начала массива. Поэтому можно существенно ускорить выделение и освобождение памяти под массив. Выделяем сначала память под массив указателей, а затем первому элементу выделяем память под все массивы одновременно. Таким образом, первый элемент будет хранить адрес начала этого массива. С его помощью "делим" массив, раздавая его оставшимся указателям.
Теперь нам необходимо всего две операции выделения памяти и две операции для освобождения.
У этого подхода есть и ещё одно важное преимущество. Массив a[0] по структуре становится похож на одномерный, так что его можно передавать как одномерный, например, для сортировки. Элементы расположены в нём по рядам, как в двумерном статическом массиве, поэтому без проблем можно его привести к типу указателя на массивы.
Можно пойти ещё дальше и заменить всё одним вызовом malloc: упаковать друг за другом сначала массив указателей, а потом массив массивов.
Здесь всего одна операция выделения и одна освобождения.
Для массивов более высокой размерности выделение памяти остаётся очень похожим.
Скорость выполнения соотносится для данных способов выделения памяти как 404:13:12 для массива размером 100 x 200 типа int. Последние два способа выделения памяти, дабы не смущать неокрепшие умы, почти не используются в курсе, но на практике динамически выделять память под многомерные массивы лучше именно таким образом.
Рассмотрим выделение памяти под трёхмерный массив. Трёхмерный массив - массив указателей на указатели, которые ссылаются на массивы указателей, которые ссылаются на массивы объектов заданного типа. Выделение памяти под трёхмерный массив размером M*N*K, соответственно, потребует M + M*N операций выделения памяти и столько же для освобождения.
Первым делом объявим переменные
Здесь a - наш будущий трёхмерный массив, data - вспомогательная переменная, которая хранит адрес, по которому начинаются непосредственно данные (белым цветом на рисунке). ptrs - вспомогательная переменная, которая хранит адрес, по которому начинаются массивы указателей (розовый на рисунке).
Для начала выделим память под массив
Затем инициализируем вспомогательные переменные
Затем надо инициализировать массив указателей на указатели
Но также нужно инициализировать каждый из массивов указателей
Теперь наш массив принимает вид:
Всё ещё не понятно? – пиши вопросы на ящик
1. В книге Харбисона и Стила "Язык С с примерами" (2011 года, стр. 162) указывается, что запись функции вида:
void getArray(int nstr, int ncol, int a[nstr][ncol]) <. >
является корректным. Я не очень понял, как тогда нужно объявлять массив "a" в основной программе для правильного вызова функции.
2. В книге по C, по-моему, Шилда указано, что в функциях можно использовать локальные массивы конструкции:
Может быть я неправильно понял изложенное в этих книгах? Прикрепляю проект, который компилировал и как С++, и как С. Посмотрите, пожалуйста, может быть я что-то делаю неправильно.
Прикреплённый файл My_ConsConly.zip (2,21 Кбайт, скачиваний: 83)
2. В книге по C, по-моему, Шилда указано, что в функциях можно использовать локальные массивы конструкции:
В Стандарте C99 разрешаются локальные в функциях массивы с неконстанстными размерами. В Стандарте C++ такого нет за ненадобностью. Но по-любому массивы в параметрах функций сводятся к указателям. Оно является коррекным в любой ревизии C/C++, но будет игнорироваться.
2. В книге по C, по-моему, Шилда указано, что в функциях можно использовать локальные массивы конструкции:
В С++. В С - можно и не константами(в C99).
Кстати, новый же стандарт C++ хотели привести в соответствие с C99
C99 так и не стал основным стандартом C. Все еще существуют компиляторы не поддерживаюшие этот стандарт, и это считается нормальным.
Учитывая, что в C++ и массивы C89 с константным размером считаются плохим тоном, то становится понятным, почему в стандарт C++ не стали вводить массивы с неизвестным на момент компиляции размером. Тем более, что у C99 и C++ и так хватает несоответствий. Вдобавок подобная таким массивам конструкция, реализованная средствами C++, практически не отличается результатом компиляции.
Если же убрать inline, то все ОК. А вот gcc все ОК в обоих случаях.
1 ответ 1
The inline keyword is available only in C++.
Вы компилируете файл как чистый C? Попробуйте __inline .
Теперь по пунктам.
- Поддержка многомерных массивов в чистом C не очень хороша. Концептуально проще всего передавать указатель на первый элемент и размеры по каждой из координат. Ваше объявление unsigned short (*arr)[4] будет скорее всего интерпретировано как unsigned short **arr .
- sizeof(array)/sizeof(unsigned short) намного лучше, чем константа 8 (размер массива может измениться!) Ещё лучше sizeof(array)/sizeof(array[0][0]) .
- Не думайте о микроэффективности, оптимизатор сам разберётся.
- Если в теле for одна строка, и нет объявления переменных на верхнем уровне, разумеется фигурные скобки можно опустить. Это скорее вопрос стиля, чем возможности.
MSVC не поддерживает пока полностью стандарт C99. В более ранних стандартах ключевого слова inline не было, и Microsoft добавило своё ключевое слово __inline . Пользуйтесь им. Если вы хотите кроссплатформенность, используйте платформоспецифические макросы:
@VladD __inline помогло. Спасибо. И что значит "чистый" С? Есть Си и С++. 1) Вы предлагаете сделать что-то вроде:
__inline void func(unsigned short **arr, unsigned short x, unsigned short y) < unsigned short length = 0, ctr; length = x + y; for(ctr = 0; ctr < length; ctr++) printf("[%hu] - %hu\n", ctr, . ) ); // как вывести массив? >а вызов функции: func(array, 2, 4); ? 2) Почему лучше sizeof(array)/sizeof(array[0][0])?
@dr_kraken: чистый С — это C в отличие от C++. 1) Я предлагаю сделать inline void func(unsigned short* arr, unsigned short x, unsigned short y) < unsigned short length = x * y, ctr; for(ctr = 0; ctr < length; ctr++) printf("[%hu] - %hu\n", ctr, arr[ctr]); >Вызов func(&array[0][0], 2, 4) . 2) Потому что код не надо будет менять, если вы перейдёте с short на double .
@dr_kraken: 1) Мне нужно получить указатель на начальный элемент, &array[0][0] именно это и делает. 2) Для функции всё равно. Нет, на самом деле всё равно. Почитайте вот и вот, там объясняют лучше, чем я.
Да, @dr_kraken, тема массивов и указателей (вместе с адресной арифметикой и передачей параметров), пожалуй, центральная для понимания сути языка Си. -- Вы уже внимательно прочли ее в K&R?
Пытаюсь создать массив, задав размерность константой, однако получаю ошибки: "выражение должно иметь константное значение", "требуется константное выражение", "невозможно выделить память для массива постоянного нулевого размера".
Задай с помощью defineа.
Размерность статического массива должна быть известна на этапе компиляции. А значение константы в общем случае может быть не извесно при компиляции. К сожалению в Си незавезли из плюсов constexpr.
SIZE большими буквами это исторически так сложилось дефайны называть капсом, само собой не обязательно, какой programming style будет принят у тебя в команде такой и используй
дефайны это не числа, это тупая подстановка строки, т.е. все что после define имя будет написано, то и подставится, так что аккуратно с ковычками скобками и прочим
rPman, не, я не про дефайн, а про общий случай с неизвестным значением на момент компиляции.
В сишке же нельзя константе неизвестное значение присвоить
Василий Банников, ааа, формально, если константой считать переменные с таким типом, то ее можно определить как extern и создать в другом .c файле (точнее объектном), т.е. на момент компиляции значение переменной будет не известно но ее тип const будет говорить компилятору что она не должна меняться (для соответствующих оптимизаций)
Василий Банников, Так что компилятор предполагает по умолчанию, что значение константы может быть измнено при следующей итерации выполнения данного участка кода. Поэтому и нельзя объявить статический массив с константным размером.
Василий Банников, В данном случае компилятору это все равно. О чем и свидетельствует ошибка компиляции.
Кстати, может быть код автора соберется, если установить более высокий уровень оптимизации и забить на соответствие стандарту. Но не факт. К тому же, писать код зависящий от опций компиляции, чаще всего плохая идея.
Как тут уже упоминали gcc пример автора соберет. Но это будет массив VLA, а не статический массив. А это уже совсем другая история.
1. Покажи полностью код
2. Не размерность, а размер
3. Что за компилятор?
Вот это на gcc нормально собирается:
Полный код - пример из учебника Побегайло
Работаю сейчас в Visual Stuio, код компилирую как С/TC, /Gd
Nulltiton, Вот так вот задавать размер массивов - этого нет в стандарте си. Это расширение (называется VLA), но его поддерживают не все компиляторы.
Василий Банников, const - это просто обещание программиста не трогать вот эту вот переменную вот в этом вот скоупе. "обычная константа" - не настолько константна в C/С++, как вам хотелось бы думать.
Wataru, VLA -- это массив на стеке или параметр функции. В примере автора массив в сегменте данных. C99 прямо запрещает такое использование (с99 6.7.5.2:2):
ты свой массив может создать нужного размера уже в процессе выполнения а не на этапе компиляции, тогда размер может быть в переменной
int *a=new int[size];
int *a это определение массива без инициализации, размер компилятору массива неизвестный, а саму инициализацию проводить оператор new а значит где то в конце нужно память освободить с помощью delete
upd. это было для c++
ну а для си получается надо пользоваться malloc и free соответственно
int *a=(int*)malloc(size*sizeof(int));
вот есть задача.
Написать профамму, которая выводит минимальный элемент
введенного с клавиатуры массива целых чисел. Ниже приведен
рекомендуемый вид экрана во время работы профаммы (данные,
введенные пользователем, выделены полужирным шрифтом).
но начинает выбивать ошибку
c:\documents and settings\a\мои документы\visual studio 2008\projects\3\3\3.cpp(3) : error C2057: требуется константное выражение
c:\documents and settings\a\мои документы\visual studio 2008\projects\3\3\3.cpp(3) : error C2466: невозможно выделить память для массива постоянного нулевого размера
обьясните смысл этой строчки на пальцах плз
самый простой способ это циклы.
я бы завёл переменную min и присвоил ей значение первого элемента матрицы, а затем if'ом в цикле сравнивал бы его с остальными элементами, и если нашел бы меньший элемент то присвоил бы переменной min найденное минимальное значение.
PS если не понятно то через часиков 5-6 закину код.
помогите плиз построить так как подсказали, для примера неплохо былобы понять такой вариант решения
самый простой способ это циклы.
я бы завёл переменную min и присвоил ей значение первого элемента матрицы, а затем if'ом в цикле сравнивал бы его с остальными элементами, и если нашел бы меньший элемент то присвоил бы переменной min найденное минимальное значение.
этот код написан на С, не С++ но работать должно ))
а вот мне подсказали шо както так можно обьявлять массив
тут мы задали n-размер массива и a назвали его?
а вот мне подсказали шо както так можно обьявлять массив
тут мы задали n-размер массива и a назвали его?
Вот простой способ: сначала вводишь размер массива, объявляешь переменную min, потом вводишь элементы, инициализируешь min значением 0го элемента, и сравниваешь.
Вот код:
а вот мне подсказали шо както так можно обьявлять массив
тут мы задали n-размер массива и a назвали его?
тут задано целое число и указатель, к примеру указатель на данное число, массив объявляется так int a[c];
где а- имя массива c- кол-во элементов массива, вроде как кол-во элементов можно не указывать но этот способ фактически никто не рекомендует из за его невыгодности.
P.S. небольшой совет: купите книгу по интересующему вас языку программирования, желательно чтобы примеров было побольше и ищите там все непонятные моменты, но именно физически купить, а не скачать с инета, с физическим экземпляром легче намного, а купленный самоучитель вам очень поможет, потому как вопросы которые вы тут задаете примитивны и описаны в любом самоучителе.
Читайте также: