#c #arrays #c 11
#c #массивы #c 11
Вопрос:
Это скорее вопрос этикета, чем что-либо другое, но при создании новых массивов какое значение, кроме нуля, я должен использовать для обозначения пустого места в массиве? Например:
int* arr; arr = new int[10];
Когда я создам новый массив, как в приведенном выше коде, массив будет заполнен десятью нулями. Проблема, с которой я сталкиваюсь, заключается в том, что я хочу использовать подчеркивания при печати массива для обозначения пустых мест, однако у меня также есть нули как часть моего набора данных в массиве. Итак, я должен просто заполнить пустой массив с некоторым произвольным значением, что вряд ли появлюсь в моем наборе данных (like -32000 for example)
, и использовать его в качестве индикатора для пустого пространства, или есть какое-то пустое значение, которое я мог бы использовать вместо этого, так что я могу понять то, что стоимость на тот удельный показатель, безусловно, пустое место?
Комментарии:
1. Я почти уверен, что при создании нового массива, как в приведенном выше коде, он не будет заполнен десятью нулями. По крайней мере, не в соответствии со стандартом C .
2. «Нулевое значение» для
int
, вероятно, равно нулю. Поэтому вы должны выбрать какое-то другое неиспользуемое значение, если это возможно. В противном случае у вас может быть другой массивbool is_used[10]
для отслеживания использования,3. Не существует общепризнанной ценности. Вам нужно будет просмотреть ожидаемый набор данных и выбрать внеполосное значение, значение, которое не может существовать в наборе. Это или иметь флаг состояния, который прилагается к данным, чтобы отметить, является ли конкретное чтение допустимым.
4. в массивах нет пустых мест. Хотя вы можете использовать массив
std::optionallt;intgt;
Ответ №1:
То, о чем вы, похоже, спрашиваете, называется стражем-некоторым значением данных, которое имеет особое значение.
Что касается выбора стража, используйте то, что, как вы знаете, не появится, и сделайте его именованной константой. Например, вы можете использовать:
constexpr int NoValue = std::numeric_limitslt;intgt;::min();
Если вам абсолютно необходим весь диапазон целых чисел или если вы не можете надежно очистить свои входные данные, чтобы гарантировать, что данные никогда не будут приняты в качестве непустого значения, рассмотрите возможность использования большего типа данных, который может представлять этот диапазон и страж, или используйте std::optional
, как предложено в другом ответе.
В качестве альтернативы, создайте отдельный массив для хранения этой информации. Для такого массива требуется только один бит на элемент, чтобы указать, является ли значение пустым или нет, и поэтому это означает только частичное увеличение объема памяти, а не расширение вашего типа данных за его пределы int
. Этот подход снижает использование памяти в сравнении с локальностью памяти, поскольку данные о «пустоте» не будут храниться рядом со значением в вашем массиве, и это может иметь последствия для кэширования.
Что касается фактического вопроса инициализации: ваш массив неинициализирован и потребует установки значений с std::fill
или аналогичных. В противном случае поведение вашей программы не определено, если вы попытаетесь использовать неинициализированное значение. Обратите внимание, что есть особый случай: new int[100]()
который приведет к нулевой инициализации памяти. Но вы не можете использовать эту конструкцию для инициализации с любым другим значением.
Рассмотрите возможность использования std::vector
, чтобы избежать проблем с управлением памятью и обеспечить инициализацию с ненулевыми значениями без добавления помех в коде:
std::vectorlt;intgt; arr(10, NoValue);
Как вы можете видеть, необходимо сделать выбор, который зависит от требований вашей программы и ее входной спецификации. Я надеюсь, что это поможет вам принять более обоснованное решение.
Ответ №2:
должен ли я просто заполнить пустой массив каким-то произвольным значением, которое вряд ли появится в моем наборе данных
Ну, маловероятно, что это не то же самое, что значение, которое, как вы точно знаете, не будет отображаться в данных, и ошибка, которую вы получите, если ошибетесь в этом, будет неприятной ошибкой. Вообще говоря, однако, у вас обычно есть некоторое представление о диапазоне допустимых значений, и действительно может быть проще использовать значение sentinel за пределами этого диапазона для указания на недействительность. (И если вы сделаете это таким образом, я бы рекомендовал быть очень разборчивым в очистке входных данных, поступающих в вашу программу, т. Е. явно проверять значение sentinel, неожиданно поступающее из внешнего источника.)
Однако в тех случаях, когда такого значения нет, или просто для того, чтобы однозначно заявить о своем намерении, канонический способ справиться с этой ситуацией в современном C — использовать std::optionallt;intgt;
. Стандартная библиотека-это optional
способ превратить любой тип в тип, допускающий обнуление.
Ответ №3:
Пожалуйста, обратите внимание, что вопросы «вкуса», как правило, не одобряются в StackOverflow.
С учетом сказанного, вот мои предпочтения:
Что-то, что не может маскироваться под допустимое значение, например NaN, является хорошим заполнителем. Если это не вариант, то, как вы сказали, значение, которое не будет/не разрешено отображаться в наборе данных, работает.
Комментарии:
1. NaN-это специальное значение с плавающей запятой. Вопрос конкретно касается целых чисел. Что касается NaN, да, это может быть уместно для данных с плавающей запятой, но создает свои собственные проблемы. Не в последнюю очередь потому, что NaN-тестирование отличается от равенства, а значения NaN в целом нарушают все логические и арифметические операторы.
2. Я вижу, как сбивает с толку мой язык. Я имел в виду НаН или что-то вроде Нан. Я также учел, что это не вариант. «Значения NaN в целом нарушают все логические и арифметические операторы» Да, в этом все дело. это будет болезненно очевидно, когда что-то будет сделано с недопустимыми значениями.