Почему Вы указываете размер при использовании malloc в C?

conrad@papa ~ $ uptime
 04:42:36 up 495 days,  8:51,  8 users,  load average: 0.02, 0.02, 0.00
21
задан Gabriele Petronella 12 November 2013 в 06:44
поделиться

17 ответов

Простая логика: если вы не паркуетесь в законное парковочное место, ничего не может случиться, но иногда вашу машину могут отбуксировать, и вы можете столкнуться с огромным штрафом. И иногда, когда вы пытаетесь найти дорогу к тому месту, где буксировали вашу машину, вас может сбить грузовик.

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

По таким вопросам, как этот, полезно обратиться к разделу Распределение памяти в C FAQ . См. 7.3b .

По поводу связанной (юмористической) заметки, см. Также список ляпов от ART .

126
ответ дан 29 November 2019 в 06:03
поделиться

Выполните:

int *p = malloc(2 * sizeof(*p)); // wrong (if type is something greater than a machine word)

[type] *p = malloc(2 * sizeof([type])); // right.
-2
ответ дан 29 November 2019 в 06:03
поделиться

Как все говорили, вы пишете в память, которая на самом деле не выделена, а это означает, что что-то может произойти, чтобы перезаписать ваши данные. Чтобы продемонстрировать проблему, вы можете попробовать что-то вроде этого:

int *p = malloc(2 * sizeof(int));
p[0] = 10; p[1] = 20; p[2] = 30;
int *q = malloc(2 * sizeof(int));
q[0] = 0; // This may or may not get written to p[2], overwriting your 30.

printf("%d", p[0]); // Correctly prints 10
printf("%d", p[1]); // Correctly prints 20
printf("%d", p[2]); // May print 30, or 0, or possibly something else entirely.

Нет никакого способа гарантировать, что ваша программа выделит место для q в точке p [2]. На самом деле он может выбрать совершенно другое место. Но для такой простой программы это кажется вероятным, и если она действительно выделяет q в том месте, где будет p [2], это ясно продемонстрирует ошибку выхода за пределы диапазона.

0
ответ дан 29 November 2019 в 06:03
поделиться

Размер, заданный для malloc (), заключается в том, чтобы диспетчер памяти отслеживал, сколько места было выделено каждому процессу в вашей системе. Эти таблицы помогают системе узнать, кто сколько места выделил и какие адреса свободны ().

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

В-третьих, по всей вероятности, вызов malloc () в первый раз, вероятно, не просто выделяет 8 байтов для вашего процесс. Это зависит от реализации, но более вероятно, что диспетчер памяти выделит полную страницу для вашего использования только потому, что легче выделить фрагменты размера страницы .... затем последующий malloc () ' s будет дальше разделять ранее созданную с помощью malloc () страницу.

0
ответ дан 29 November 2019 в 06:03
поделиться

Вы запрашиваете место для двух целых чисел. p [3] предполагает, что у вас есть место для 4 целых чисел!

===================

Вам нужно указать malloc, сколько вам нужно, потому что он может Трудно догадаться , сколько памяти вам нужно.

malloc может делать все, что захочет, если он возвращает по крайней мере объем памяти, который вы запрашиваете.

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

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

1
ответ дан 29 November 2019 в 06:03
поделиться

Потому что malloc выделяет пространство в куче, которая является частью памяти, используемой вашей программой, которая динамически выделяется. Затем базовая ОС дает вашей программе запрошенное количество (или нет, если вы получите некоторую ошибку, которая подразумевает, что вы всегда должны проверять возврат malloc для состояния ошибки) виртуальной памяти, которую она сопоставляет с физической памятью (т.е. умная магия, включающая сложные вещи, такие как разбиение на страницы, мы не хотим углубляться, если мы не пишем ОС.

0
ответ дан 29 November 2019 в 06:03
поделиться

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

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

Очень жаль , , что он так часто работает правильно, потому что эту ошибку может быть сложно написать тестовые примеры, чтобы ее отловить. Лучшие подходы к его тестированию включают либо замену malloc () реализацией, которая отслеживает ограничения размера блока и агрессивно проверяет работоспособность кучи при каждой возможности, либо использование такого инструмента, как valgrind , чтобы наблюдать за поведением программы «извне» и обнаруживать неправильное использование буферной памяти. В идеале такое неправильное использование должно дать сбой на ранней стадии и громкий сбой.

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

Редактировать: OP исправил побочную проблему с * (p + 2) , противоречащим p [1] , поэтому я отредактировал свой ответ, чтобы убрать эту точку .

1
ответ дан 29 November 2019 в 06:03
поделиться

В зависимости от платформы p [500], вероятно, тоже "работает".

2
ответ дан 29 November 2019 в 06:03
поделиться

Позвольте мне провести аналогию с тем, почему это «работает».

Предположим, вам нужно нарисовать рисунок, поэтому вы берете лист бумаги, кладете его на стол, и начинайте рисовать.

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

Когда закончите, вы делаете шаг назад и смотрите на свой рисунок, и он выглядит хорошо, именно так, как вы хотели, и именно так, как вы его нарисовали.

Пока кто-нибудь не подойдет и не возьмет свой листок бумаги, который они оставили на столе, прежде чем вы добрались до него.

. Теперь отсутствует часть рисунка. Фрагмент, который вы нарисовали на бумаге того другого человека.

Кроме того, у этого человека теперь есть фрагменты вашего рисунка на бумаге, вероятно, вместо этого он возился с тем, что хотел иметь на бумаге.

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

C построен как бензопила на стероидах. Вы почти ничего не можете сделать. Это также означает, что вам нужно знать, что вы делаете, иначе вы пропилите дерево насквозь себе под ногу, прежде чем осознаете это.

27
ответ дан 29 November 2019 в 06:03
поделиться

Память представлена ​​как непрерывная перечислимая линия слотов, в которых могут храниться числа. Функция malloc использует некоторые из этих слотов для своей собственной информации отслеживания, а также иногда возвращает слоты, размер которых больше вам нужно, чтобы, когда вы вернете их позже, он не застрянет в непривычно маленьком участке памяти. Ваш третий int либо приземляется на собственные данные mallocs, либо на оставшееся пустое пространство в возвращенном фрагменте, либо в области ожидающей памяти, которую malloc запросил у ОС, но еще не распределил вам.

2
ответ дан 29 November 2019 в 06:03
поделиться

Попробуйте следующее:

int main ( int argc, char *argv[] ) {
  int *p = malloc(2 * sizeof *p);
  int *q = malloc(sizeof *q);
  *q = 100;

  p[0] = 10;    p[1] = 20;    p[2] = 30;    p[3] = 40;
  p[4] = 50;    p[5] = 60;    p[6] = 70;


  printf("%d\n", *q);

  return 0;
}

На моем компьютере он печатает:

50

Это потому, что вы переписали память, выделенную для p, и нажали q.

Примечание что malloc не может помещать p и q в непрерывную память из-за ограничений выравнивания.

4
ответ дан 29 November 2019 в 06:03
поделиться

Когда вы используете * (p + 3), вы обращаетесь за пределы границ даже с использованием 2 * sizeof (* p), следовательно, вы получаете доступ недопустимый блок памяти, идеально подходящий для ошибок сегмента.

Вы указываете размер b / c, иначе функция не знает, какой размер блока из кучи памяти следует выделить вашей программе для этого указателя.

0
ответ дан 29 November 2019 в 06:03
поделиться

Поскольку malloc () выделяется в байтах. Итак, если вы хотите выделить (например) 2 целых числа, вы должны указать размер в байтах 2 целых чисел. Размер целого числа можно найти с помощью sizeof (int), поэтому размер в байтах 2 целых чисел равен 2 * sizeof (int). Сложите все это вместе, и вы получите:

int * p = malloc(2 * sizeof(int));

Примечание: учитывая, что вышеупомянутое выделяет место только для ДВУХ целых чисел, вы очень непослушны, назначая третье. Тебе повезло, что он не падает. :)

0
ответ дан 29 November 2019 в 06:03
поделиться

Все это восходит к тому, что C позволил вам выстрелить себе в ногу. То, что вы можете это сделать, не означает, что вы должны это делать. Определенно не гарантируется, что значение p + 3 будет тем, что вы указали, если вы специально не назначили его с помощью malloc.

4
ответ дан 29 November 2019 в 06:03
поделиться

На самом деле malloc не выделяет достаточно места для вашего третьего целого числа, но вам «повезло», и ваша программа не вылетела. Вы можете быть уверены только в том, что malloc выделил именно то, что вы просили, не более того. Другими словами, ваша программа записала в часть памяти, которая не была выделена для нее.

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

4
ответ дан 29 November 2019 в 06:03
поделиться

Тебе (не) повезло. Доступ к p [3] не определен, поскольку вы не выделили эту память для себя. Чтение / списание конца массива - это один из способов загадочного сбоя программ на C.

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

Что еще хуже, вы можете перезаписать некоторые другие данные и не заметить. Представьте, что это случайно перезаписывает сумму денег, которую вы кому-то должны; -)

13
ответ дан 29 November 2019 в 06:03
поделиться

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

Отказ от ответственности: Мое последнее настоящее программирование на C было выполнено около 15 лет назад.

31
ответ дан 29 November 2019 в 06:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: