calloc — Полноценность обнуления памяти

Каково преимущество обнуления памяти (т.е. calloc() malloc())? Разве Вы не измените значение на что-то еще так или иначе?

11
задан unwind 12 November 2012 в 15:31
поделиться

6 ответов

Есть два лагеря: один говорит, что инициализация переменных при их объявлении помогает находить ошибки. Люди в этом лагере удостоверяются, что все, что они объявляют, инициализировано. Они инициализируют указатели на NULL , int s равными 0 и т. Д. Идея состоит в том, что все является определенным, и когда они видят указатель NULL в отладчике , они сразу понимают, что это неправильно. Это также может помочь вашей программе аварийно завершиться во время тестирования из-за разыменования указателя NULL , а не из-за загадочного сбоя в производственных циклах.

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

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

Теперь есть два исключения:

  • Если вы принадлежите к лагерю «инициализировать все», вы не calloc () , но malloc () , потому что вы инициализируете числа с плавающей запятой или указатели, и вы знаете, что все нулевые биты не обязательно означают 0 для них. Или вам не нужны дополнительные накладные расходы.
  • Если вы принадлежите к группе «набор, когда вам нужно», вам может потребоваться calloc () , когда вы выделяете некоторые данные, и хотите, чтобы все они были нулями.Например, если вы хотите вычислить по строкам сумму n на m динамически распределенных данных int .

1 Вы можете увидеть мои ответы на многие вопросы здесь, на SO, чтобы узнать, к какому лагерю я принадлежу :-).

16
ответ дан 3 December 2019 в 03:18
поделиться

Хорошо знать, что все, что вы выделяете, инициализируется нулем. Многие ошибки возникают из-за кода, который использует неинициализированную память. Кроме того, некоторые значения по умолчанию в структурах / классах могут быть нулевыми, поэтому вам не нужно изменять все значения после malloc.

Например, выделите структуру, в которой есть несколько указателей с / malloc. Проверки NULL не всегда будут работать, если для них не установлено значение NULL. Если вы вызываете calloc, вам не нужно выполнять дополнительные шаги инициализации для значений указателя.

1
ответ дан 3 December 2019 в 03:18
поделиться

Помимо преимуществ инициализации переменных, calloc также помогает отслеживать ошибки.

Если вы случайно используете часть выделенной памяти без ее правильной инициализации, приложение всегда будет терпеть неудачу. Например, при нарушении прав доступа из-за нулевого указателя. С malloc память имеет случайные значения, и это может привести к сбою программы случайным образом.

Случайные сбои очень сложно отследить, и calloc помогает их избежать.

0
ответ дан 3 December 2019 в 03:18
поделиться
  1. Зная, какое значение уже есть, программист может пойти на некоторые сокращения и сделать определенные оптимизации. Чаще всего callocинг структуры с указателями: они инициализируются в NULL.
  2. А что, если программист забыл инициализировать что-то при распределении? Вместо случайных вещей, ноль - отличное значение по умолчанию.

В системе управления процессами реального времени, над которой я работал давным-давно, мы остановились на том, что при включении питания логика инициализирует всю оперативную память значением 0xCC, инструкцией прерывания 3 8086. Это заставило бы процессор войти в монитор (примитивный отладчик), если бы он каким-то образом выполнил неинициализированную память. (К сожалению, 8086 без проблем выполняет память, содержащую нули, поскольку это инструкции add [bx+si],al. Даже 32-битный режим заставляет их быть инструкциями add [ax],al.)

Я не помню, находили ли мы когда-нибудь убегающую программу, но значения, соответствующие 0xCC в различных значениях: 52,428 (unsigned 16 bit), -19,660 (signed 16 bit), -107374176 (32-bit float), и -9.25596313493e+61 (64-bit float) выскакивали во множестве неожиданных мест. Кроме того, некоторый код, ожидающий, что символы будут 7-битными ASCII - то есть ошибка - предупредил нас о своем присутствии, когда пытался обработать 0xCC.

8
ответ дан 3 December 2019 в 03:18
поделиться

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

3
ответ дан 3 December 2019 в 03:18
поделиться

Во-первых, вы не можете вызывать указатели calloc, по крайней мере, если вы хотите следовать стандарту C.

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

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

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

0
ответ дан 3 December 2019 в 03:18
поделиться
Другие вопросы по тегам:

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