Когда использовать массив над указателем или наоборот - PullRequest
4 голосов
/ 28 апреля 2011

Насколько я понимаю, указатели могут использоваться, помимо прочего, для того, чтобы вы могли динамически распределять память, когда вам это нужно (и знаете, сколько вам нужно), вместо того, чтобы распределять ее статически с массивами заранее.

Я пытаюсь определить, когда лучше сэкономить время вычислений при динамическом выделении и выбрать больший объем памяти по сравнению с большим объемом памяти и использовать некоторое время вычислений для выделения только необходимой памяти.

Можеткто-то пролил немного света на эту тему?Существуют ли общие правила, которые могут помочь?

Ответы [ 5 ]

1 голос
/ 28 апреля 2011

Вы должны использовать динамически выделенную память, когда:

  • вы не знаете, сколько памяти вам понадобится во время компиляции
  • количество памяти меняется при работе
  • вам нужно много памяти

Вы должны использовать статически выделенную память, когда:

  • вы знаете размер во время компиляции
  • объем необходимой памяти невелик

Для использования динамически выделяемой памяти необходимо использовать системные вызовы, это когда программа запрашивает что-то в операционной системе. У вас есть штраф за скорость, потому что процесс может потерять «время обработки», которое дается другому процессу. Есть много вещей, которые ОС должна сделать, чтобы выполнить вызов. Выполнение системного вызова для запроса памяти - процесс гораздо более тяжелый, чем просто запись в массив, хранящийся в стеке процессов.

1 голос
/ 28 апреля 2011

Как правило, вы хотите использовать массив, когда вы знаете либо общий размер данных, с которыми вы будете иметь дело, либо, по крайней мере, максимальный размер данных. Это особенно применимо, если вы действительно не ожидаете огромных изменений в размере - если (например) изменение составляет от 10 до 20 элементов, вероятно, проще всего просто выделить 20 независимо и покончить с этим (если каждый элемент не действительно большой).

Если вы намного меньше представляете себе размер данных заранее или (и, что важно, возможно) легко справляетесь со слишком большим количеством планов размещения в стеке, динамическое распределение становится гораздо более полезным. Основным недостатком динамического распределения является то, что если вам когда-нибудь понадобится узнать размер, вам нужно следить за ним самостоятельно, и вы должны убедиться, что вы освободите память, когда закончите с ней. Многие (особенно сложные, ноющие) проблемы в C сводятся к использованию памяти после ее освобождения или забыванию освободить память, когда вы закончили с ней.

0 голосов
/ 29 апреля 2011

Хотя на этот вопрос есть принятый ответ. Позвольте мне поговорить о немного другой вещи. В Си иногда можно использовать массив с размером, определенным во время выполнения. Например:

void foo (int a[], int n) {
    int buf[n];
    /* do something with buf[] */
}

Этот вид массивов размещается в стеке и имеет переменный размер. Отличие от использования malloc заключается в том, что вам не нужно free() память; об этом позаботятся, когда вызов функции существует. Конечно, это также означает, что вы не можете вернуть адрес массива.

0 голосов
/ 28 апреля 2011

Массивы - это просто непрерывные куски памяти.Когда вы объявляете массив, у вас есть указатель

int foo[5];

foo (без индекса) - указатель на первый элемент в этом массиве.

foo[0] = 1;
*foo = 1;

Те же действия, что и:

foo[1] = 2;
*(foo + 1) = 2;

Когда вы создаете массив с помощью int foo[5];, вы создаете его в стеке.Это локально для текущей функции, и после возврата из функции она становится недействительной.Если у вас malloc() память, вы создаете массив в куче (и имеете указатель на него)

int *foo = malloc(sizeof(int) * 5);
foo[0] = 1;
*foo = 1;

Вы должны управлять этой памятью самостоятельно, а free() - когдасделано с этим:

free(foo);
0 голосов
/ 28 апреля 2011

Вы используете динамический контейнер, когда ваши данные являются динамическими, или вам нужно передавать данные из разных областей вашей программы.

1 - Динамические данные Допустим, у вас есть список ваших соседей.Они строят новый дом на твоей улице, и ты должен добавить парня в список, но ты выделил достаточно места только для 15 соседей.Эта динамическая память позволит вам увеличить размер этого контейнера.Это не совсем так.Фактически, он находит новый кусок памяти необходимого размера, а затем копирует старый контейнер.

Или другой пример.Допустим, вы пишете программу, которая отслеживает адресную книгу.У одного из ваших пользователей есть десять контактов.Другой пользователь - корпорация, и в этой адресной книге нужно хранить 50 000 сотрудников.Вы не хотите выделять 50000 мест для пользователя, у которого есть десять контактов, поэтому вы точно выделяете, сколько вам нужно.

2 - Передача данных Когда вы выделяете статические данные, они помещаются в стек, а затемнедоступен после выхода из области видимости.Поэтому, если вы вызовете некоторую функцию, которая генерирует ваш массив, а затем передадут адрес памяти массива обратно его вызывающей стороне, вы получите ошибку времени выполнения.Это происходит потому, что после выхода из этой функции массив выходит из области видимости, и поэтому он выталкивается из стека.

Однако, если вы выделяете его динамически, он попадает в кучу и не освобождаетсяДо тех пор, пока вы не освободите его или пока программа не выйдет.Таким образом, вы можете просто сохранить указатель на начало массива и использовать его во всей программе, не беспокоясь о том, что он выйдет из области видимости, пока вы этого не захотите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...