Каков правильный инициализатор для нестатического 2D-массива?

#c 11 #variables #initializer-list #non-static

#c 11 #переменные #инициализатор-список #нестатический

Вопрос:

Visual Studio позволяет: int a[3][3] = { 0 }; как для локальной переменной, так и для нестатической переменной класса. Однако GCC допускает это только для локальных переменных, но требует, чтобы int a[3][3] = { {0} }; для инициализации переменной класса. Является ли GCC слишком ограничительным или VS слишком разрешительным?

 #include <iostream>
using namespace std;

class InitArray {
 public:
   InitArray();
   void PrintArray() const;
 private:
   int a[3][3] = { 0 };       // compiles in Visual Studio 2017, but not GCC
                              // modify to = { {0} }; to compile in GCC
InitArray::InitArray() {
   PrintArray();
   for (int i = 0; i < 3; i  ) {
      for (int j = 0; j < 3; j  ) {
         a[i][j] = 1;
      }
   }
}

void InitArray::PrintArray() const {
   for (int i = 0; i < 3; i  ) {
      for (int j = 0; j < 3; j  ) {
         cout << a[i][j] << " ";
      }
      cout << endl;
   }
}

int main() {
   InitArray A;
   A.PrintArray();
   int a[3][3] = {0};          // OK in BOTH compilers
   for (int i = 0; i < 3; i  ) {
      for (int j = 0; j < 3; j  ) {
         cout << a[i][j] << " ";
      }
      cout << endl;
   }

   return 0;
}
  

Комментарии:

1. Ответа нет, но совет: сделайте это правильно для платформ, для которых вы разрабатываете. Итак, вопрос в том, какой результат вы получаете при использовании {{0}} ? И какой результат вы получаете для использования {0} в локальном случае? Обязательно ли быть независимым от платформы?

2. Какую ошибку компиляции вы получаете в GCC?

3. Даниэлю: При отображении, как показано ниже, GCC выдает ошибку: массив должен быть инициализирован с помощью заключенного в скобки инициализатора int a[3][3] = { 0 };

4. To Tobi: {{0}} работает на обеих платформах, так что это переносимый код, который я напишу в дальнейшем. В основном, вопрос был любопытным — почему компилятор GCC допускает локальные переменные по сравнению с переменными класса?

Ответ №1:

Ваш код усваивает только первую ячейку в массиве, измените строку

 int a[3][3] = {0}; 
  

Для

  int a[3][3] = {1};
  

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

что касается вопроса компиляции, я компилирую с помощью GCC, и оба компилируются для меня. Разница между типами инициализации заключается в том, что

 int a[3][3] = {1,2,3,4,5};
  

При компиляции вы получите

 1 2 3 
4 5 0 
0 0 0
  

Но
int b[3][3] = {{1,2,3,4}};
Не будет компилироваться из-за

слишком много инициализаторов для ‘int [3]’ Это произойдет потому, что {{}} инициализирует только первый массив a[3] в матрице a[3][3]. Если вы хотите инициализировать все это, вам нужно будет вызвать это следующим образом:

 int a[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
  

Комментарии:

1. Дэниел: Спасибо. Если бы я хотел различные ненулевые значения, то я бы явно предоставил их. Однако в ситуациях, когда мне нужны нулевые значения, я часто инициализирую первый элемент как ноль, зная, что остаток по умолчанию будет равен нулю. Экономит ввод. Знаете ли вы экземпляр (компилятор), который инициализируется ТОЛЬКО указанными значениями и не обнуляет остаток? Если это так, я бы изменил свою практику.

2. Ах, я понимаю, это немного сбивает с толку, потому что кажется, что вы хотите инициализировать весь массив равным 0. Если вы просто предполагаете, что значение по умолчанию равно 0, зачем вообще использовать = {0}?. Что касается вашего вопроса, я думаю, что все компиляторы c будут инициализировать первое значение как 0, а затем использовать default для остальных

3. Мой опыт работы с gcc следующий: int a[5]; поскольку глобальная переменная инициализируется нулями — int b[5]; поскольку стековая (локальная) переменная НЕИНИЦИАЛИЗИРОВАНА — int c[5] = {1, 2}; следует правилу частичной инициализации массива, которое инициализирует элементы как заданные и заполняет оставшуюся часть массива нулями.