Inicjalizacja całej tablicy 2D z jedną wartością

82

Z następującą deklaracją

Otrzymuję tablicę ze wszystkimi zerami, ale z następującym

Nie otrzymuję tablicy z jedną wartością. Wartością domyślną jest nadal 0.

Dlaczego to zachowanie i jak mogę zainicjować wszystkie 1?

EDYCJA: Właśnie zrozumiałem, że użycie memsetwartości 1 spowoduje ustawienie każdego bajtu na 1, a zatem rzeczywista wartość każdej komórki tablicy nie będzie wynosić 1, ale 16843009. Jak ustawić go na 1?

Kraken
źródło
1
@ckruse: Pytanie nie brzmi: jak , tylko dlaczego .
masoud
@MM. odpowiedź znajduje się w wątku, który podlinkowałem.
ckruse
W rzeczywistości problem dotyczył why and howobu. :)
Kraken
@Kraken Pytanie w twojej zmianie powinno być prawdopodobnie opublikowane jako pytanie oddzielne od tego.
Lundin
1
@Kraken Właściwie znalazłem to pytanie tutaj . Poleciłbym zrobić to, co zasugerowałem w mojej odpowiedzi (oczywiście!) I nie polegać na rozszerzeniach GCC.
Lundin

Odpowiedzi:

126

Masz ten problem, bo int array [ROW][COLUMN] = {1};nie nie oznacza „ustawienie wszystkich elementów do jednego”. Spróbuję wyjaśnić krok po kroku, jak to działa.

Jawny, zbyt przejrzysty sposób inicjalizacji tablicy wyglądałby tak:

Jednak C pozwala na pominięcie niektórych elementów w tablicy (lub struct / union). Możesz na przykład napisać:

Oznacza to, zainicjuj pierwsze elementy na 1 i 2, a pozostałe elementy „tak, jakby miały statyczny czas trwania”. W języku C istnieje reguła mówiąca, że ​​wszystkie obiekty o statycznym czasie trwania, które nie są jawnie inicjowane przez programistę, muszą być ustawione na zero.

W powyższym przykładzie pierwszy wiersz jest ustawiany na 1,2, a następny na 0,0, ponieważ nie podaliśmy im żadnych jawnych wartości.

Następnie w C jest reguła zezwalająca na luźny styl klamry. Pierwszy przykład można równie dobrze zapisać jako

chociaż oczywiście jest to kiepski styl, trudniej jest go przeczytać i zrozumieć. Ale ta zasada jest wygodna, ponieważ pozwala nam pisać

co oznacza: „zainicjuj pierwszą kolumnę w pierwszym wierszu na 0, a wszystkie inne elementy tak, jakby miały statyczny czas trwania, tj. ustaw je na zero”.

dlatego jeśli spróbujesz

oznacza to „zainicjuj pierwszą kolumnę w pierwszym wierszu na 1 i ustaw wszystkie inne elementy na zero”.

Lundin
źródło
2
Dzięki za to, cokolwiek mogę zrobić, aby zainicjować całą tablicę z 1? biorąc pod uwagę, że moje wiersze i kolumny mają setki rozmiarów?
Kraken
1
@Kraken Ze sztuczkami makro. Zobacz to .
Lundin
Czy to tylko ja, czy potrzebujesz drugiego zestawu nawiasów:int array [ROW][COLUMN] = {{0}};
user1794469
@ user1794469 Nie, nie masz.
Lundin
1
@ user1794469 Tak, i to dobrze, ponieważ w większości przypadków pomijanie nawiasów klamrowych jest złą praktyką. Ale kompilator nie musi podawać diagnostyki. Jeśli chodzi o dobre / złe praktyki w tym przypadku, zobacz moją odpowiedź na to pytanie .
Lundin
40

Jeśli chcesz zainicjować tablicę -1, możesz użyć następującego,

Ale to zadziała 0i -1tylko

user2021512
źródło
17
Łatwiej jest użyć „sizeof (tablica)” zamiast „sizeof (tablica [0] [0]) * wiersz * liczba”.
Vladyslav Savchenko
Działa dla dowolnego bajtu stałego, chociaż nie jest dla mnie jasne, co byłoby przydatne poza 0000i1111
user1794469
4
trzeba uwzględnić <cstring>w c ++
mtk
12

To inicjalizuje tylko pierwszy element do 1. Wszystko inne otrzymuje 0.

W pierwszej kolejności robisz to samo - inicjalizujesz pierwszy element na 0, a resztę na 0.

Powód jest prosty: w przypadku tablicy kompilator zainicjuje każdą wartość, której nie określisz, wartością 0.

Z chartablicą możesz użyć memsetdo ustawienia każdego bajtu, ale generalnie nie zadziała to z rozszerzeniemint tablicą (chociaż jest w porządku dla 0).

Ogólna forpętla zrobi to szybko:

Lub prawdopodobnie szybciej (w zależności od kompilatora)

teppic
źródło
1
@Kraken - nie - 0inicjalizuje również tylko pierwszą wartość. Następnie inicjalizuje całą resztę 0domyślnie.
teppic
@EricPostpischil więc ustawia wszystkie bajty na 1, więc jeśli rozważę 32-bitową liczbę całkowitą, to jeśli moje valuepole memsetma wartość 1, to rzeczywista wartość w macierzy nie będzie wynosić 1, ale 2^0 + 2^8 + 2^16 + 2^24?
Kraken
@Kraken: Zasadniczo tak. memsetustawia każdy bajt w miejscu docelowym na podaną wartość, która nie zadziała, aby ustawić wartość intna 1. memsetNie można używać do ustawiania wartości obiektów wielobajtowych, chyba że chcesz, aby każdy bajt obiektu miał tę samą wartość.
Eric Postpischil
@EricPostpischil Więc nie ma sposobu na zrobienie tego poza ręczną inicjalizacją każdego z nich? Biorąc pod uwagę, że moje wiersze i kolumny są nawet w kilku tysiącach?
Kraken
@Kraken Wysłałem wyjaśnienie, dlaczego {1} nie działa. I rzeczywiście nie ma innego sposobu niż ręczna inicjalizacja. Nie musisz jednak wpisywać tysięcy liczb, są sztuczki makro, ale być może jest to temat na inne pytanie.
Lundin
8

Zauważ, że GCC ma rozszerzenie wskazanej notacji inicjalizującej, co jest bardzo przydatne w kontekście. Jest to również dozwolone clangbez komentarza (po części dlatego, że stara się być kompatybilny z GCC).

Notacja rozszerzenia umożliwia ...wyznaczenie zakresu elementów do zainicjowania z następującą wartością. Na przykład:

Wynik jest, jak można się spodziewać,:

Należy zauważyć, że Fortran 66 (Fortran IV) miał liczbę powtórzeń dla inicjatorów dla tablic; zawsze wydawało mi się dziwne, że C nie dostał ich po dodaniu wyznaczonych inicjatorów do języka. Pascal używa 0..9notacji do oznaczenia zakresu od 0 do 9 włącznie, ale C nie używa ..jako tokena, więc nie jest zaskakujące, że nie został użyty.

Zauważ, że spacje wokół ...notacji są zasadniczo obowiązkowe; jeśli są dołączone do liczb, to liczba jest interpretowana jako liczba zmiennoprzecinkowa. Na przykład, 0...9byłoby tokenized jak 0., ., .9i liczb zmiennoprzecinkowych nie są akceptowane jako indeksami macierzy. Z wymienionymi stałymi ...ROW-1nie sprawi kłopotów, ale lepiej jest wyrobić sobie bezpieczne nawyki.


Uzupełnienia:

Zwracam uwagę na to, że GCC 7.3.0 odrzuca:

gdzie jest dodatkowy zestaw nawiasów klamrowych wokół skalarnego inicjatora 1( error: braces around scalar initializer [-Werror]). Nie jestem pewien, czy to prawda, biorąc pod uwagę, że normalnie można określić nawiasy klamrowe wokół wartości skalarnej w int a = { 1 };, co jest wyraźnie dozwolone w standardzie. Nie jestem też pewien, czy jest to nieprawidłowe.

Zastanawiam się również, czy nie byłaby lepsza notacja [0]...[9]- to jest jednoznaczne, nie można jej pomylić z żadną inną prawidłową składnią i unika pomyłki z liczbami zmiennoprzecinkowymi.

Może komisja normalizacyjna to rozważy?

Jonathan Leffler
źródło
7

Aby zainicjować tablicę 2d z zerem, użyj poniższej metody: int arr[n][m] = {};

UWAGA : Powyższa metoda będzie działać tylko przy inicjalizacji z wartością 0;

Gaurav Suthar
źródło
3

Zamiast tego użyj tablicy wektorowej :

Jogendra Kumar
źródło
3
Możliwe, ale OP nie wspomniał o C ++.
Sangeet
0

To służy do inicjalizacji elementów tablicy char do znaków spacji.

inhalator
źródło