Это - хорошая практика для инициализации массива в C/C++?

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

На дальнейшем расследовании я нашел, что существует структура, которая содержит некоторые целые числа и массив символов 64 байтов, и не все байты массива символов привыкали в большинстве случаев, и неиспользованные поля от массива содержат случайные данные, и это вызывало несоответствие.

Это принесло мне, задают вопрос, является ли это хорошей практикой для инициализации массива в C/C++ также, поскольку это сделано в Java?

9
задан Jon Seigel 16 April 2010 в 17:35
поделиться

8 ответов

Это - хорошая практика для инициализации памяти/переменных перед использованием их - неинициализированные переменные являются большим источником ошибок, которые часто очень трудно разыскать.

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

единственное серьезное основание не инициализировать переменные перед использованием их, находится в исполнительных критических ситуациях, где инициализация является технически "ненужной" и подвергается значительным издержкам. Но в большинстве случаев инициализация переменных не нанесет значительный ущерб (особенно, если они будут только сразу объявлены, прежде чем они будут использоваться), но сохранит вас много времени разработки путем устранения общего источника ошибок.

23
ответ дан 4 December 2019 в 06:49
поделиться

с использованием неопределенного значения в массиве приводит к неопределенному поведению. Таким образом, программа свободна создавать различные результаты. Это может означать, что ваши файлы в конечном итоге заканчиваются немного по-другому или что программа сбивает сбои, или программа форматирует ваш жесткий диск, или программа вызывает демоны вылетки пользователей носа ( http://catb.org/jargon/html /N/nasal-demons.html)

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

MyStruct array[10];
printf( "%f", array[2].v ); // POTENTIAL BANG!
array[3].v = 7.0;
...
printf( "%f", array[3].v ); // THIS IS OK.

Не забывайте, что для огромных массивов стручков есть хороший сокращение, чтобы инициализировать всех членов до нуля

MyPODStruct bigArray[1000] = { 0 };
5
ответ дан 4 December 2019 в 06:49
поделиться

Укажите вариант языка в параметрах сервиса.

$ tomcat / bin / javaw.exe Переместить вкладку java и укажите -duser.language = en -duser.region = ca в параметрах Java:

-121--1732913-

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

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

3
ответ дан 4 December 2019 в 06:49
поделиться

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

Но если вы используете массив CHAR, как NULL завершают строку, то вы сможете написать его в файл с правильной функцией.

Хотя в C ++ может быть лучше использовать более эфирное решение. Я векторы, строки и т. Д.

1
ответ дан 4 December 2019 в 06:49
поделиться

Имейте в виду, что сохранение массивов неинициализировано, может иметь преимущества, такие как производительность.

Это только плохое чтение из неинициализированных массивов. Имея их вокруг, когда никогда не читают из неинициализированных мест в порядке.

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

1
ответ дан 4 December 2019 в 06:49
поделиться

Я бы сказал, что хорошая практика в C ++ использует STD :: Vector <> вместо массива. Это не допустимо для C, конечно.

0
ответ дан 4 December 2019 в 06:49
поделиться

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

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

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

0
ответ дан 4 December 2019 в 06:49
поделиться

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

struct NODE Pop(STACK * Stack)
{
  struct NODE node = EMPTY_STACK;

  if(Stack && Stack->stackPointer)
    node = Stack->node[--Stack->stackPointer];

  return node;
}

Это был код, написанный другим парнем. Эта функция является самой популярной функцией в нашем приложении (вы представляете текстовый индекс на 500 000 000 предложений в троичном дереве, стек FIFO используется для обработки рекурсии, поскольку мы не хотим использовать рекурсивные вызовы функций). {{1} } Это было типично для его стиля программирования из-за его систематической инициализации переменных. Проблема с этим кодом заключалась в скрытом memcpy инициализации и двух других копиях структур (которые, кстати, не были вызовами memcpy gcc, иногда странно), поэтому у нас было 3 копии + скрытый вызов функции в самой популярной функции проекта. Переписываем ее в

struct NODE Pop(STACK * Stack)
{
  if(Stack && Stack->stackPointer)
    return Stack->node[--Stack->stackPointer];
  return EMPTY_STACK;
}

Только одна копия (и дополнительное преимущество в SPARC, где она выполняется, функция является листовой функцией благодаря избегаемому вызову memcpy и не нужно создавать новое окно реестра). Так что функция была в 4 раза быстрее.

Еще одна проблема. Я обнаружил унцию, но не помню, где именно (так что нет примера кода, извините).Переменная, которая была инициализирована при объявлении, но использовалась в цикле с переключателем в конечном автомате. Проблема в том, что значение инициализации не было одним из состояний автомата, и в некоторых крайне редких случаях автомат работал некорректно. После удаления инициализатора предупреждение, выдаваемое компилятором, сделало очевидным, что переменную можно использовать до того, как она будет правильно инициализирована. Тогда исправить автомат было несложно. Мораль: защитная инициализация переменной может подавить очень полезное предупреждение компилятора.

Заключение: разумно инициализируйте переменные. Систематическое выполнение этого - не что иное, как следование культу карго (мой приятель на работе - худший карго-культер, который можно себе представить, он никогда не использует goto, всегда инициализирует переменную, использует много статических объявлений (это быстрее, вы знаете (это на самом деле даже очень медленно на SPARC 64bit), делает все функции встроенными , даже если они имеют 500 строк (с использованием __ attribute __ ((always_inline)) , когда компилятор не хочет)

1
ответ дан 4 December 2019 в 06:49
поделиться