Mam dużą tablicę w C (nie C ++, jeśli to robi różnicę). Chcę zainicjować wszystkich członków o tej samej wartości.
Mógłbym przysiąc, że kiedyś znałem prosty sposób na zrobienie tego. Mógłbym użyć memset()
w moim przypadku, ale czy nie ma na to sposobu wbudowanego w składnię C.
enum { HYDROGEN = 1, HELIUM = 2, CARBON = 6, NEON = 10, … };
istruct element { char name[15]; char symbol[3]; } elements[] = { [NEON] = { "Neon", "Ne" }, [HELIUM] = { "Helium", "He" }, [HYDROGEN] = { "Hydrogen", "H" }, [CARBON] = { "Carbon", "C" }, … };
. Jeśli usuniesz wielokropek…
, te fragmenty kompilują się pod C99 lub C11.memset()
konkretna dyskusja: stackoverflow.com/questions/7202411/ ... Myślę, że to działa tylko dla 0.Odpowiedzi:
O ile ta wartość nie wynosi 0 (w którym to przypadku można pominąć część inicjatora, a odpowiednie elementy zostaną zainicjowane na 0), nie ma łatwego sposobu.
Nie zapomnij o oczywistym rozwiązaniu:
Elementy z brakującymi wartościami zostaną zainicjowane na 0:
To zainicjuje wszystkie elementy do 0:
W C ++ pusta lista inicjalizacji również inicjuje każdy element na 0. Nie jest to dozwolone w C:
Pamiętaj, że obiekty ze statycznym czasem przechowywania będą inicjowane na 0, jeśli nie zostanie określony inicjator:
A to „0” niekoniecznie oznacza „wszystko-zero-bity”, więc użycie powyższego jest lepsze i bardziej przenośne niż memset (). (Wartości zmiennoprzecinkowe zostaną zainicjowane na +0, wskaźniki na wartość zerową itp.)
źródło
Jeśli twoim kompilatorem jest GCC, możesz użyć następującej składni:
Sprawdź szczegółowy opis: http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Designated-Inits.html
źródło
int
s do danych statycznych, czyli 256 K - dokładnie taki wzrost, jaki zaobserwowałeś.int
s,int foo1 = 1, foo2 = 1, ..., foo65536 =1;
otrzymasz taki sam wzrost rozmiaru.bool array[][COLS] = { [0...ROWS-1][0...COLS-1] = true}
, choć nie jestem pewien, czy jest to bardziej czytelne niż pełna forma.Do statycznego inicjowania dużej tablicy o tej samej wartości, bez wielokrotnego wklejania i kopiowania, możesz użyć makr:
Jeśli chcesz zmienić wartość, musisz dokonać wymiany tylko w jednym miejscu.
Edycja: możliwe przydatne rozszerzenia
(dzięki uprzejmości Jonathan Leffler )
Możesz łatwo to uogólnić za pomocą:
Wariant można utworzyć za pomocą:
który działa ze strukturami lub tablicami złożonymi.
nazwy makr podlegają negocjacji.
źródło
VAL_1X
nie jest to jedna liczba całkowita, ale lista. Podobnie jak stany Amigable, jest to również droga do systemów wbudowanych, w których chcesz zdefiniować wartości początkowe EEPROM lub pamięci Flash. W obu przypadkach nie możesz użyćmemset()
.Jeśli chcesz się upewnić, że każdy element tablicy jest jawnie zainicjowany, po prostu pomiń wymiar z deklaracji:
Kompilator wydedukuje wymiar z listy inicjalizatora. Niestety w przypadku tablic wielowymiarowych można pominąć tylko wymiar zewnętrzny:
jest OK, ale
nie jest.
źródło
int myPoints[10][] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9} };
Widziałem kod korzystający z tej składni:
Szczególnie przydatna jest sytuacja, gdy tworzysz tablicę, która używa indeksu jako indeksu:
Utrzymuje to porządek, nawet jeśli zdarzy się, że niektóre wartości wyliczenia zostaną zapisane w porządku.
Więcej na temat tej techniki można znaleźć tutaj i tutaj .
źródło
char const *array[] = { ... };
a nawetchar const * const array[] = { ... };
, prawda?Myślę, że to jest lepsze niż
zwiększyć wielkość zmian tablicy.
źródło
memset(myArray, VALUE, ARRAY_SIZE);
Możesz wykonać całą statyczną inicjalizację, jak opisano szczegółowo powyżej, ale może to być prawdziwy błąd, gdy zmienia się rozmiar tablicy (gdy tablica się rozjaśnia, jeśli nie dodasz odpowiednich dodatkowych inicjatorów, otrzymasz śmieci).
Program memset zapewnia działanie środowiska wykonawczego za wykonanie zadania, ale prawidłowe trafienie rozmiaru kodu nie jest odporne na zmiany rozmiaru tablicy. Używałbym tego rozwiązania w prawie wszystkich przypadkach, gdy tablica była większa niż, powiedzmy, kilkadziesiąt elementów.
Jeśli naprawdę ważne było, aby tablica została zadeklarowana statycznie, napisałbym program, który napisałby program dla mnie i uczynił go częścią procesu kompilacji.
źródło
memset
inicjalizacji tablicy?Oto inny sposób:
Widzieć:
Rozszerzenia C.
Wyznaczone inits
Następnie zadaj pytanie: kiedy można używać rozszerzeń C?
Powyższy przykładowy kod znajduje się w systemie osadzonym i nigdy nie zobaczy światła z innego kompilatora.
źródło
Do inicjowania „normalnych” typów danych (takich jak tablice int) można użyć notacji nawiasowej, ale zeruje wartości po ostatnim, jeśli w tablicy jest jeszcze miejsce:
źródło
Jeśli tablica jest int lub cokolwiek o rozmiarze int lub rozmiar wzorca memu pasuje dokładnie do int (tzn. Wszystkie zera lub 0xA5A5A5A5), najlepszym sposobem jest użycie memset () .
W przeciwnym razie wywołaj memcpy () w pętli przesuwającej indeks.
źródło
Lekko wymowna odpowiedź; napisz oświadczenie
w swoim ulubionym języku obsługującym tablice (moim jest Fortran, ale jest wiele innych) i połącz go z kodem C. Prawdopodobnie zechcesz to podsumować jako funkcję zewnętrzną.
źródło
Istnieje szybki sposób na zainicjowanie tablicy dowolnego typu o podanej wartości. Działa bardzo dobrze z dużymi tablicami. Algorytm jest następujący:
W przypadku tablicy
1 000 000
elementówint
jest 4 razy szybsza niż zwykła inicjalizacja pętli (i5, 2 rdzenie, 2,3 GHz, pamięć 4GiB, 64 bity):loop runtime 0.004248 [seconds]
memfill() runtime 0.001085 [seconds]
źródło
memfill()
kod zajmuje około 1200 µs. Jednak podczas kolejnych iteracji pętla zajmuje około 900-1000 µs, podczas gdymemfill()
kod zajmuje 1000-1300 µs. Prawdopodobnie na pierwszą iterację ma czas wypełnienia pamięci podręcznej. Odwróć testy imemfill()
po raz pierwszy jest wolny.Nikt nie wspomniał o indeksie dostępu do elementów zainicjowanej tablicy. Mój przykładowy kod da przykładowy przykład.
Dane wyjściowe to:
źródło
<iostream>
Nie jest ważneC
jakstd::cout
,std::cin
itp jest częściąstd::namespace
iC
nie obsługujenamespaces
. Spróbuj użyć<stdio.h>
doprintf(...)
zamiast.Przeglądając całą paplaninę, krótka odpowiedź brzmi: jeśli włączysz optymalizację w czasie kompilacji, nie zrobisz nic lepszego:
Dodano bonus: kod jest czytelny :)
źródło
przykład: int array [10]; memset (tablica, -1, 10 * sizeof (int));
źródło
Daje o / p 5 5 5 5 5 5 ...... aż do wielkości całej tablicy
źródło
Wiem, że użytkownik
Tarski
odpowiedział na to pytanie w podobny sposób, ale dodałem kilka dodatkowych szczegółów. Wybacz trochę mojego C, bo jestem trochę zardzewiały, ponieważ jestem bardziej skłonny do używania C ++, ale proszę bardzo.Jeśli znasz rozmiar tablicy przed czasem ...
Powyżej jest kilka zastrzeżeń; jednym z nich jest to, że
UINT myArray[size];
nie jest inicjowany bezpośrednio po deklaracji, jednak następny blok kodu lub wywołanie funkcji inicjuje każdy element tablicy do tej samej wartości, którą chcesz. Drugim zastrzeżeniem jest to, że będziesz musiał napisaćinitializing function
dla każdegotype
obsługiwanego, a także będziesz musiał zmodyfikowaćprintArray()
funkcję, aby obsługiwała te typy.Możesz wypróbować ten kod za pomocą kompilatora internetowego znalezionego tutaj .
źródło
W przypadku opóźnionej inicjalizacji (tj. Inicjalizacji konstruktora elementu klasy) należy rozważyć:
źródło
Wiem, że pierwotne pytanie wyraźnie wymienia C, a nie C ++, ale jeśli (tak jak ja) przybyłeś tutaj, szukając rozwiązania dla tablic C ++, oto fajna sztuczka:
Jeśli Twój kompilator obsługuje wyrażenia składania , możesz użyć magii szablonu i
std::index_sequence
wygenerować listę inicjalizującą z żądaną wartością. Możesz to wyrównaćconstexpr
i poczuć się jak szef:Możesz rzucić okiem na kod w pracy (w Wandbox)
źródło
W pytaniu nie widzę żadnych wymagań, więc rozwiązanie musi być ogólne: inicjalizacja nieokreślonej, być może wielowymiarowej tablicy zbudowanej z nieokreślonych elementów struktury o początkowej wartości elementu:
Wynik:
EDYCJA:
start+element_size
zmieniona na(char*)start+element_size
źródło
sizeof(void)
ogóle jest ważny.memcpy()
pokrywają się z miejscem docelowym. Przy naiwnym wdrożeniumemcpy()
może działać, ale system nie wymaga, aby działał.Kiedyś (i nie mówię, że to dobry pomysł), ustawiamy pierwszy element, a następnie:
memcpy (&element [1], &element [0], sizeof (element)-sizeof (element [0]);
Nie jestem nawet pewien, czy to zadziała (to zależy od implementacji memcpy), ale działa poprzez wielokrotne kopiowanie elementu początkowego do następnego - nawet działa dla tablic struktur.
źródło
memcpy
ale określono kolejność kopiowania od dołu do góry lub od góry do dołu w przypadku nakładania się, ale tak nie jest.memmove()
nie działa.Jeśli masz na myśli równolegle, myślę, że operator przecinka, gdy jest używany w połączeniu z wyrażeniem, może to zrobić:
lub jeśli masz na myśli jedną konstrukcję, możesz to zrobić w pętli for:
// Uwaga: przecinek na liście argumentów nie jest operatorem równoległym opisanym powyżej;
Możesz zainicjować deklinację tablicy:
Możesz zadzwonić do malloc / calloc / sbrk / przydzielać / etc, aby przydzielić ustalony region pamięci do obiektu:
i uzyskać dostęp do członków przez:
Itp.
źródło