Z następującą deklaracją
int array[ROW][COLUMN]={0};
Otrzymuję tablicę ze wszystkimi zerami, ale z następującym
int array[ROW][COLUMN]={1};
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 memset
wartoś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?
c
arrays
initialization
Kraken
źródło
źródło
why and how
obu. :)Odpowiedzi:
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:
#define ROW 2 #define COLUMN 2 int array [ROW][COLUMN] = { {0, 0}, {0, 0} };
Jednak C pozwala na pominięcie niektórych elementów w tablicy (lub struct / union). Możesz na przykład napisać:
int array [ROW][COLUMN] = { {1, 2} };
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
int array [ROW][COLUMN] = {0, 0, 0, 0};
chociaż oczywiście jest to kiepski styl, trudniej jest go przeczytać i zrozumieć. Ale ta zasada jest wygodna, ponieważ pozwala nam pisać
int array [ROW][COLUMN] = {0};
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
int array [ROW][COLUMN] = {1};
oznacza to „zainicjuj pierwszą kolumnę w pierwszym wierszu na 1 i ustaw wszystkie inne elementy na zero”.
źródło
int array [ROW][COLUMN] = {{0}};
Jeśli chcesz zainicjować tablicę
-1
, możesz użyć następującego,memset(array, -1, sizeof(array[0][0]) * row * count)
Ale to zadziała
0
i-1
tylkoźródło
0000
i1111
<cstring>
w c ++int array[ROW][COLUMN]={1};
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
char
tablicą możesz użyćmemset
do ustawienia każdego bajtu, ale generalnie nie zadziała to z rozszerzeniemint
tablicą (chociaż jest w porządku dla 0).Ogólna
for
pętla zrobi to szybko:for (int i = 0; i < ROW; i++) for (int j = 0; j < COLUMN; j++) array[i][j] = 1;
Lub prawdopodobnie szybciej (w zależności od kompilatora)
for (int i = 0; i < ROW*COLUMN; i++) *((int*)a + i) = 1;
źródło
0
inicjalizuje również tylko pierwszą wartość. Następnie inicjalizuje całą resztę0
domyślnie.value
polememset
ma wartość 1, to rzeczywista wartość w macierzy nie będzie wynosić 1, ale2^0 + 2^8 + 2^16 + 2^24
?memset
ustawia każdy bajt w miejscu docelowym na podaną wartość, która nie zadziała, aby ustawić wartośćint
na 1.memset
Nie można używać do ustawiania wartości obiektów wielobajtowych, chyba że chcesz, aby każdy bajt obiektu miał tę samą wartość.Zauważ, że GCC ma rozszerzenie wskazanej notacji inicjalizującej, co jest bardzo przydatne w kontekście. Jest to również dozwolone
clang
bez 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:#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; }
Wynik jest, jak można się spodziewać,:
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
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..9
notacji 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...9
byłoby tokenized jak0.
,.
,.9
i liczb zmiennoprzecinkowych nie są akceptowane jako indeksami macierzy. Z wymienionymi stałymi...ROW-1
nie sprawi kłopotów, ale lepiej jest wyrobić sobie bezpieczne nawyki.Uzupełnienia:
Zwracam uwagę na to, że GCC 7.3.0 odrzuca:
int array[ROW][COLUMN] = { [0 ... ROW-1] = { [0 ... COLUMN-1] = { 1 } } };
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 wint 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.int array[ROW][COLUMN] = { [0]...[4] = { [0]...[9] = 1 } };
Może komisja normalizacyjna to rozważy?
źródło
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;
źródło
Zamiast tego użyj tablicy wektorowej :
vector<vector<int>> array(ROW, vector<int>(COLUMN, 1));
źródło
char grid[row][col]; memset(grid, ' ', sizeof(grid));
To służy do inicjalizacji elementów tablicy char do znaków spacji.
źródło