Инициализация всего массива 2D с одним значением
Со следующим объявлением
int array[ROW][COLUMN]={0};
Я получаю массив со всеми нулями, но со следующим
int array[ROW][COLUMN]={1};
Я не получаю массив со всем одним значением. Значение по умолчанию равно 0.
Почему это поведение и как я могу инициализировать все 1?
EDIT: я только понял, что использование memset
со значением как 1, задает каждый байт как 1 и, следовательно, фактическое значение каждой ячейки массива не будет 1, а 16843009
. Как установить его на 1?
Ответы
Ответ 1
Вы получаете это поведение, потому что int array [ROW][COLUMN] = {1};
означает не означает "установить все элементы в один". Позвольте мне попытаться объяснить, как это работает шаг за шагом.
Явный, явный способ инициализации вашего массива будет выглядеть следующим образом:
#define ROW 2
#define COLUMN 2
int array [ROW][COLUMN] =
{
{0, 0},
{0, 0}
};
Однако C позволяет вам исключить некоторые элементы в массиве (или struct/union). Например, вы можете написать:
int array [ROW][COLUMN] =
{
{1, 2}
};
Это означает, что инициализируйте первые элементы 1 и 2, а остальные элементы "как если бы они имели статическую продолжительность хранения". В C есть правило, говорящее, что все объекты статической продолжительности хранения, которые явно не инициализированы программистом, должны быть установлены на ноль.
Итак, в приведенном выше примере первая строка получает значение 1,2, а следующая - 0,0, так как мы не даем им никаких явных значений.
Далее, в C существует правило, позволяющее использовать стиль lax brace. Первый пример также можно записать как
int array [ROW][COLUMN] = {0, 0, 0, 0};
хотя, конечно, это плохой стиль, его труднее читать и понимать. Но это правило удобно, поскольку оно позволяет нам писать
int array [ROW][COLUMN] = {0};
что означает: "инициализировать первый столбец в первой строке до 0 и все остальные элементы, как если бы они имели статическую продолжительность хранения, то есть устанавливали их в ноль".
поэтому, если вы попытаетесь выполнить
int array [ROW][COLUMN] = {1};
это означает "инициализировать первый столбец в первой строке до 1 и установить все остальные элементы в ноль".
Ответ 2
Если вы хотите инициализировать массив до -1
, вы можете использовать следующее,
memset(array, -1, sizeof(array[0][0]) * row * count)
Но это будет работать только 0
и -1
Ответ 3
int array[ROW][COLUMN]={1};
Это инициализирует только первый элемент в 1. Все остальное получает 0.
В первом случае вы делаете то же самое - инициализируете первый элемент до 0, а остальные по умолчанию - 0.
Причина проста: для массива компилятор будет инициализировать каждое значение, которое вы не укажете с помощью 0.
С массивом char
вы можете использовать memset
для установки каждого байта, но это обычно не работает с массивом int
(хотя это нормально для 0).
Общий цикл for
сделает это быстро:
for (int i = 0; i < ROW; i++)
for (int j = 0; j < COLUMN; j++)
array[i][j] = 1;
Или, возможно, быстрее (в зависимости от компилятора)
for (int i = 0; i < ROW*COLUMN; i++)
*((int*)a + i) = 1;
Ответ 4
Обратите внимание, что GCC имеет расширение для обозначения обозначенного инициализатора, что очень полезно для контекста. Это также разрешено clang
без комментариев (частично потому, что оно пытается быть совместимым с GCC).
Нотация расширения позволяет использовать ...
для обозначения диапазона элементов, которые должны быть инициализированы, со следующим значением. Например:
#include <stdio.h>
enum { ROW = 5, COLUMN = 10 };
int array[ROW][COLUMN] = { [0 ... ROW-1] = { [0 ... COLUMN-1] = 1 } };
int main(void)
{
for (int i = 0; i < ROW; i++)
{
for (int j = 0; j < COLUMN; j++)
printf("%2d", array[i][j]);
putchar('\n');
}
return 0;
}
Неудивительно, что результат:
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
Обратите внимание, что Fortran 66 (Fortran IV) имел количество повторов для инициализаторов для массивов; мне всегда казалось странным, что C не получил их, когда в язык были добавлены назначенные инициализаторы. А Паскаль использует нотацию 0..9
для обозначения диапазона от 0 до 9 включительно, но C не использует ..
в качестве токена, поэтому неудивительно, что он не использовался.
Обратите внимание, что пробелы вокруг обозначения ...
являются по существу обязательными; если они привязаны к числам, то число интерпретируется как число с плавающей запятой. Например, 0...9
будет маркироваться как 0.
, .
, .9
, а числа с плавающей запятой не допускаются в качестве индексов массива.
С указанными константами ...ROW-1
не вызовет проблем, но лучше перейти к безопасным привычкам.
Дополнения:
Попутно отмечу, что GCC 7.3.0 отклоняет:
int array[ROW][COLUMN] = { [0 ... ROW-1] = { [0 ... COLUMN-1] = { 1 } } };
где есть дополнительный набор скобок вокруг скалярного инициализатора 1
(error: braces around scalar initializer [-Werror]
). Я не уверен, что правильно, учитывая, что вы можете обычно указывать скобки вокруг скаляра в int a = { 1 };
, что явно разрешено стандартом. Я тоже не уверен, что это неверно.
Мне также интересно, будет ли лучшая нотация [0]...[9]
- она однозначна, ее нельзя спутать с любым другим допустимым синтаксисом и избежать путаницы с числами с плавающей запятой.
int array[ROW][COLUMN] = { [0]...[4] = { [0]...[9] = 1 } };
Может, комитет по стандартам рассмотрит это?
Ответ 5
Вместо этого используйте векторный массив:
vector<vector<int>> array(ROW, vector<int>(COLUMN, 1));
Ответ 6
Для инициализации 2d массива с нуля используйте метод ниже:
int arr[n][m] = {};
ПРИМЕЧАНИЕ: вышеупомянутый метод будет работать только для инициализации с 0;