Ініціалізація всього 2D-масиву одним значенням


82

З наступною декларацією

Я отримую масив з усіма нулями, але з наступним

Я не отримую масив з одним значенням. Значення за замовчуванням все ще 0.

Чому така поведінка і як я можу ініціалізувати всі 1?

РЕДАКТУВАТИ: Я щойно зрозумів, що використання memsetзі значенням 1 буде встановлювати кожен байт як 1, а отже, фактичне значення кожної комірки масиву не буде 1, але 16843009. Як встановити значення 1?


1
@ckruse: Питання не в тому, як , а в тому, чому .
masoud 20.03.13

@MM. відповідь дається в темі, яку я зв’язав.
ckruse

Проблема була насправді в why and howобох. :)
Kraken

@Kraken Питання у вашій редакції, можливо, слід розміщувати як окреме запитання від цього.
Лундін,

1
@Kraken Насправді я знайшов це запитання тут . Я б рекомендував робити так, як пропонується у моїй відповіді (звичайно!), А не покладатися на розширення GCC.
Лундін,

Відповіді:


126

Ви отримуєте таку поведінку, оскільки int array [ROW][COLUMN] = {1};це не означає "встановити всі елементи до одного". Дозвольте мені спробувати пояснити, як це працює поетапно.

Явний, надто зрозумілий спосіб ініціалізації вашого масиву буде таким:

Однак, C дозволяє вилучити деякі елементи з масиву (або структури / об'єднання). Наприклад, ви можете написати:

Це означає, що ініціалізуйте перші елементи до 1 і 2, а решту елементів "ніби вони мають статичну тривалість зберігання". У C є правило, яке говорить, що всі об’єкти статичної тривалості зберігання, які явно не ініціалізовані програмістом, повинні мати нульове значення.

Отже, у наведеному вище прикладі перший рядок має значення 1,2, а наступний - 0,0, оскільки ми не надали їм явних значень.

Далі є правило на мові C, що дозволяє розслаблений стиль фігурних дужок. Перший приклад цілком можна написати як

хоча, звичайно, це поганий стиль, його важче читати та розуміти. Але це правило зручне, оскільки воно дозволяє нам писати

що означає: "ініціалізуйте перший стовпець у першому рядку значенням 0, а всі інші елементи так, ніби вони мають статичну тривалість зберігання, тобто встановіть їх на нуль."

тому, якщо ви спробуєте

це означає "ініціалізувати перший стовпець у першому рядку рівним 1 і встановити всі інші елементи на нуль".


2
Дякую за це, що я можу зробити, щоб узагальнити весь масив 1? враховуючи, що мої рядки та стовпці мають сотні розмірів?
Кракен

1
@Kraken З макро фокусами. Дивіться це .
Лундін,

Це лише я, чи вам потрібен другий набір дужок:int array [ROW][COLUMN] = {{0}};
user1794469

@ user1794469 Ні, ні.
Лундін,

1
@ user1794469 Так, і це добре, оскільки в більшості випадків пропускати дужки - це погана практика. Але компілятор не повинен давати діагностику. Щодо доброї / поганої практики у цій справі, див. Мою відповідь на це запитання .
Лундін,

40

Якщо ви хочете ініціалізувати масив, -1тоді ви можете використовувати наступне:

Але це спрацює 0і -1лише


17
Простіше використовувати "sizeof (array)" замість "sizeof (array [0] [0]) * row * count".
Владислав Савченко

Вона працює для будь-яких постійна байт , хоча це не ясно мені , що було б корисно , крім 0000і1111
user1794469

5
потрібно включити <cstring>в c ++
mtk

12

Це ініціює лише перше елемент до 1. Все інше отримує 0.

У першому випадку ви робите те саме - ініціалізуєте перший елемент до 0, а решта за замовчуванням дорівнює 0.

Причина проста: для масиву компілятор ініціює кожне значення, яке ви не вказали 0.

З charмасивом, який ви можете використовувати memsetдля встановлення кожного байта, але це, як правило, не працює з intмасивом (хоча це добре для 0).

Загальний forцикл зробить це швидко:

Або, можливо, швидше (залежно від компілятора)


1
@Kraken - Це не так - 0ініціалізує лише перше значення. Потім він ініціалізує всі інші 0за замовчуванням.
теппік

@EricPostpischil, отже, він встановлює всі байти з 1, отже, якщо я вважаю 32-бітне ціле число, то, якщо моє valueполе в memset1, то фактичне значення в матриці не буде 1, але 2^0 + 2^8 + 2^16 + 2^24?
Кракен

@Kraken: По суті, так. memsetвстановлює для кожного байта в пункті призначення значення, яке йому задано, що не буде працювати для встановлення intзначення 1. memsetне може використовуватися для встановлення значень багатобайтових об'єктів, якщо ви не хочете, щоб кожен байт об'єкта встановлювався однаковим.
Ерік Постпішлі

@EricPostpischil Отже, це неможливо зробити, крім ініціалізації кожного вручну? Враховуючи, що моїх рядків і стовпців навіть кілька тисяч?
Кракен

@Kraken Я опублікував пояснення, чому {1} ​​не працює. І насправді немає іншого шляху, як ручна ініціалізація. Вам не потрібно вводити тисячі цифр, є макроприйоми, але це, можливо, тема для іншого питання.
Лундін,

8

Зауважте, що GCC має розширення до позначеного позначення ініціалізатора, що є дуже корисним для контексту. Це також допускається clangбез коментарів (частково тому, що він намагається бути сумісним із GCC).

Позначення розширення дозволяє використовувати ...для позначення діапазону елементів, які потрібно ініціалізувати з наступним значенням. Наприклад:

Результат, як не дивно:

Зверніть увагу, що Fortran 66 (Fortran IV) мав кількість повторень для ініціалізаторів масивів; мені завжди здається дивним, що C не отримав їх, коли до мови додали призначені ініціалізатори. І Паскаль використовує 0..9позначення для позначення діапазону від 0 до 9 включно, але C не використовує.. як маркер, тому не дивно, що він не використовувався.

Зауважте, що пробіли навколо ...позначень по суті є обов’язковими; якщо вони прикріплені до чисел, то число інтерпретується як число з плаваючою комою. Наприклад, 0...9буде лексеми , як 0., ., .9і числа з плаваючою комою не допускається в якості індексів масиву. З названими константами ...ROW-1це не призведе до проблем, але краще увійти в безпечні звички.


Додатки:

Побіжно зазначаю, що GCC 7.3.0 відхиляє:

де є додатковий набір фігурних дужок навколо скалярного ініціалізатора 1( error: braces around scalar initializer [-Werror]). Я не впевнений, що це правильно, враховуючи те, що ви зазвичай можете вказати фігурні дужки навколо скаляра int a = { 1 };, що явно дозволено стандартом. Я також не впевнений, що це неправильно.

Мені також цікаво, чи було б кращим позначенням [0]...[9]- це однозначно, не можна сплутати з будь-яким іншим дійсним синтаксисом і уникає плутанини з числами з плаваючою комою.

Може, комітет зі стандартів це розгляне?


7

Для ініціалізації 2d-масиву нулем використовуйте наведений нижче спосіб: int arr[n][m] = {};

ПРИМІТКА : Наведений вище метод буде працювати лише для ініціалізації з 0;



0

Це для ініціалізації елементів масиву символів пробілами.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.