Массивы в языке Си
Массивы служат для хранения множества данных одного типа.
Массив характеризуется типом хранимых данных и размером массива — количество хранимых данных.
Массивы делятся на статические — создаваемые при запуске программы и динамические — создаваемые в процессе выполнения программы.
Массивы бывают одномерные и многомерные. Легко визуализировать массивы с размерностью до трех. Одномерные массивы это хранение элементов в линию, двумерные — прямоугольником, трехмерные — параллелепипедом. Четырехмерный массив — это одномерный массив трехмерных массивов и т.д.
Статические массивы
Статические массивы создаются при запуске программы в статической памяти и существуют всё время выполнения программы.
Статические массивы создаются в области памяти называемой стеком. Размер стека ограничен сильнее чем размер кучи (heap) (динамическая память), поэтому нельзя создать большой статический массив (например в 100 миллионов записей). И в общем случае размер динамического массива может быть больше чем статического.
Размер статического массива должен быть известен на момент запуска программы, поэтому он должен либо быть явно прописан в коде цифрами, либо вставляться через макроподстановки (некоторые компиляторы позволяют использовать переменную для задания размера статического массива). В любом случае вы НЕ МОЖЕТЕ задать размер статического массива во время выполнения программы.
Инициализация статического массива
int a[5]; // Статический массив a состоящий из 5 элементов int. int a[5] = <>; // Статический массив инициализированный нулями static int a[5]; // Статический массив инициализированный нулями int a[3] = ; //Создание и явная инициализация статического массива со значениями 1, 3, 8. int a[] = ; //Создание и явная инициализация статического массива со значениями 1, 3, 8. int a[2][3];//Двумерный массив из двух строк (row) и трех столбцов (column) int a[2][3]=< //Двумерный массив с явной инициализацией , , >; int a[][3]=< //Двумерный массив с явной инициализацией . Первую размерность можно не указывать , , >;
Ниже приведен пример программы с прямой и косвенной адресацией элементов массива.
#include // Требуется для prinf() #define AR_SIZE 10 // Размер массива int main() < int a[10]; // Статический массив размером 10 #define AR_SIZE 10 // Размер массива можно задать через макроопределение int b[AR_SIZE]; // Статический массив размером AR_SIZE for(int n = 0; n < AR_SIZE; n++)< // Перебираем массив printf("a[%d] = %d\n", n, a[n]); // Выводим значения printf("a + %d = %d\n", n, *(a + n)); // Аналогично предыдущей строке (косвенная адресация) >return 0; >
Динамические массивы
Динамические массивы создаются во время работы программы в динамической памяти функцией malloc() и выделенная под них память освобождается либо вручную, вызовом функции free(), либо во время завершения программы.
Динамические массивы создаются в динамической памяти называемой кучей. Размер кучи ограничен операционной системой и для 32-х битный систем не может превышать 4 гигабайта.
Размер динамического массива может задаваться во время выполнения программы, в том числе размер может задаваться переменными, которые инициализируются во время работы программы — например пользовательский ввод, это одно из важнейших отличий от статических массивов.
Необходимость ручного выделения памяти под динамические массивы функцией malloc() и освобождения памяти функцией free() усложняет программу и может вызывать утечки памяти. Поэтому, если есть возможность — всегда используйте статические массивы.
Утечкой памяти называют ситуацию когда динамическая память, используемая программой, постоянно растет. Такая ситуация возникает когда выделение памяти (функцией malloc()) происходит чаще чем освобождение (функцией free()). В результате чего динамическая память кончается и программа завершается с ошибкой и теряет работоспособность. Выделение памяти может происходить в цикле и программисту приходится вручную следить чтобы она своевременно освобождалась. Существует множество языков где процессом освобождения памяти занимается так называемый сборщик мусора (garbage collector), но на данный момент данные языки сильно проигрывают Си по производительности. Для маленьких и короткоживущих программ проблема утечки памяти может быть не актуальна, но для программ и сервисов которые работают постоянно это бывает серьезной проблемой, решением которой бывают кривые подходы вроде периодических ручных или автоматических перезапусков программы — не делайте так.
Ниже приведен пример программы с созданием, обработкой и уничтожение одномерного динамического массива.
#include //printf() #include // malloc(), free() int main() < const int AR_SIZE = 5; // Размер массива int* ar = malloc(5 * sizeof(int)); // Создание динамического массива на 5 элементов. Необходимо далее их инициализировать. printf("&ar = %p, ar = %p \n", &ar, ar); for(int i = 0; i < AR_SIZE; i++)< ar[i] = i * i; // Инициализация массива printf("&ar[%d] = %p, ar[%d] = %d \n", i, &ar[i], i, ar[i]); // Использование массива >free(ar); // Освобождение памяти >
Двумерный динамический массив
Работа с двумерным динамическим массивом заметно сложнее чем с одномерным, а на практике размерность массива может быть и больше.
#include //printf() #include // malloc(), free() int main() < const int ROW = 2, COL = 4; // Размер массива рядов, столбцов char **ar = malloc(ROW * sizeof (char *)); // Выделение памяти под указатели на строки (ряды) printf("&ar = %p, ar = %p \n", &ar, ar); // Адрес массива for (int i = 0; i < ROW; i++)< // Перебираем строки (ряды) ar[i] = malloc(COL * sizeof(char)); // Выделение памяти под хранение столбцов printf("&ar[%d] = %p, ar[%d] = %p \n", i, &ar[i], i, ar[i]); // Адреса массивов for(int n = 0; n < COL; n++)< // Перебираем элементы столбца(ов) ar[i][n] = i * COL + n; // Заполняем значения массива возростающими значениями >> for (int i = 0; i < ROW; i++)< // Перебираем строки (ряды) for(int n = 0; n < COL; n++)< // Перебираем элементы столбца(ов) printf("&ar[%d][%d] = %p, ar[%d][%d] = %d \n", i, n, &ar[i][n], i, n, ar[i][n]); // Выводим значения массива >> for (int i = 0; i < ROW; i++)< // Перебираем строки (ряды) free(ar[i]); // Освобождение памяти >free(ar); // Освобождение памяти >
Понравилась страница?
Добавить в закладки
Или поделиться!
Что такое Статический и Динамический массив?

Память под статический массив выделяется на стеке. При выходе из области видимости стек очищается и память под массивом освобождается автоматически (не нужна операция освобождения памяти, операция есть, но о ней позаботится компилятор самостоятельно).
Память для динамического массива выделяется в динамической памяти (в куче) (new[]). Когда массив становится не нужным память должна быть освобождена (delete[]), иначе произойдет утечка памяти.
В связи с вышеизложенными принципиальными отличиями, есть несколько следствий:
1. Имя статического массива это не указатель. Это можно понять например сравнив, что возвращает sizeoff() для статического массива и для динамического. Хотя в некоторых ситуациях компилятор ведет себя так, как будто имя статического массива это указатель, например: можно передать имя статического массива в функцию, принимающую указатель.
2. У динамического массива нет имени. Операция new[] возвращает указатель. Имя есть у указателя.
3. Внимание! Оба варианта массивов имеют фиксированный размер. Изменять его нельзя!
То что в std::vector вы можете укладывать кучу элементов постепенно, не указывая нигде предварительного размера является следствием того, что std::vector скрывает от вас всю работу, которую он при этом делает. При добавлении нового элемента, для которого нет места, он выделяет память для нового массива большего размера, копирует старый массив в новый, удаляет старый массив, добавляет новый элемент. Если идет интенсивная работа с push_back(), то это может ОООЧЕНЬ дорого стоить. std::vector — это удобно, но необходимо всегда помнить, за счет чего достигается это удобство. std::vector — это не динамический массив — это обертка над ним для более удобной работы с динамическим массивом.
В языке Си (C99) есть такая штука как Variable Length Array (VLA) — это статический массив с изменяемым размером. Т.е. вы можете, например, в функции объявить int arr[N], где N будет передаваться в функцию как параметр.
В стандарте С++ VLA нет! Но, например, тот же gcc с опциями по умолчанию разрешает его использования в С++ проектах. С опциями, заставляющими gcc более жестко следовать стандарту, он может запрещать использовать VLA в С++ проектах. Но не рассчитывайте, что все компиляторы будут так делать. Например микрософтовский компилятор в принципе не умеет в VLA (хотя я уже пару лет не проверял это).
VLA может показаться классной штукой.
Но, например, в ядре Линукс в свое время проводили целую компанию по выпиливанию VLA из исходников. Торвальдс высказывался негативно про VLA. Все это при желании можно нагуглить.
Стоит помнить, что размер стека ограничен, а VLA то же выделяется на стеке. Кроме того выделение памяти для обычного статического массива это просто увеличение счетчика стека на константу (и все, одна операция сложения регистра с константой, а компилятор одной операцией выделяет память для всех переменных в текущей области видимости). С VLA все сложнее с выделением и удалением. Так же sizeof() для обычного статического массива это операция времени компиляции (при выполнении будет уже заранее известная константа), для VLA — это полноценный вызов функции.
Ответ написан более двух лет назад
Нравится 4 1 комментарий
Wataru @wataru Куратор тега C++
Коммкнтарий про вектор: постоянно делать push_back не особо медленнее, чем сначала выделить память и просто заполнять массив.
Медленнее, конечно, но не ОООЧЕНЬ дорого.
Это потому что вектор каждый раз, когда в нем нет места, удваивает массив. В итоге общее количество копирований элементов будет линейно и общий объем выделенной памяти — тоже. Чем больше вы элементов складываете, тем меньше разница.
Если вы знаете, сколько элементов будет — то reserve стоит сделать. Но не стоит избегать push_back, как огня из-за его медленности.
Статический и динамический массив в С?
Я учусь по книге «Язык программирования Си для начинающих. Грег Перри. Ден Миллер» и остановился на указателях и динамической памяти. У меня возник вопрос.
Зачем писать так:
int length; scanf("%d", &length); int *a = (int*) malloc(length * sizeof(int));
Когда можно писать вот так:
int length; scanf("%d", &length); int a[length];
В чем разница и когда нужно использовать статический и динамический массив?
- Вопрос задан более трёх лет назад
- 891 просмотр
Комментировать
Решения вопроса 0
Ответы на вопрос 2

Внимание! Изменился адрес почты!
Так сделать просто нельзя 🙂
Обьявить массив переменного размера — невозможно. Все обьявления должны быть вычислены заранее, потому что помещаются в «кучу». И они все будут присутствовать в слинкованном бинарнике. И можно спланировать эксплойт выходом за границу.
Статические массивы — зло.
Кроме того, вместо malloc привыкайте сразу использовать calloc — это спасет от SIGSEGV, возникающих у нубов «на ровном месте» просто из-за того, что забыли проинициализировать память, полученную от системы.
Ответ написан более трёх лет назад
Нравится 2 1 комментарий
В Си — возможно. Читайте про VLA.
Разница во времени жизни и в месте размещения в памяти такого массива.
Динамический массив размещается в куче и живёт до тех пор, пока вы его руками не удалите (вызовом free(a) ).
Статический* массив живёт на стеке и удаляется при выходе переменной из области видимости. Плюс ко всему, поскольку стек обычно имеет ограниченный размер, создание очень большого статического массива приведёт к ошибке переполнения стека (stack overflow).
P. S. Только такой массив называется не статический, а Variable Length Array (массив переменной длины).
Ответ написан более трёх лет назад
Комментировать
Нравится Комментировать
Ваш ответ на вопрос
Войдите, чтобы написать ответ

- Android
- +3 ещё
Какие есть доки по сборке APK/AAB с использованием Android NDK?
- 1 подписчик
- 30 дек. 2023
- 65 просмотров
Динамический массив статических массивов
Вы сами себе противоречите! Статический массив — это постоянная, неизменная область память, доступ к которой возможен на протяжении всей работы с программой. Статическую переменную нельзя объявлять динамически. В этом и есть особенность!
13 мая 2012 в 14:04
У меня есть статические массивы объявленные обычным образом: int arr[LENGHT] . Я лишь хочу собрать указатели на них в одном динамическом массиве.
13 мая 2012 в 14:07
Ну так соберите. Хотя проще всего инициализировать массивом-константой, который в программе уже будет, так что заводить ещё динамический массив — лишняя морока. И, кстати, что такое динамический массив (желательно ссылку на место в стандарте языка)? А то я часто тут вижу «динамический массив», а что это такое — не понимаю.