Jak zainicjować wszystkie elementy tablicy na tę samą wartość?

968

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.

Matt
źródło
16
Żadna z dotychczasowych odpowiedzi nie wspomina o wyznaczonej notacji inicjalizującej, która jest możliwa w przypadku C99 i wyższych. Na przykład: enum { HYDROGEN = 1, HELIUM = 2, CARBON = 6, NEON = 10, … };i struct 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.
Jonathan Leffler
Właściwie odpowiedź Abelenky'ego polega na użyciu wyznaczonego inicjatora, ale nie jest w pełni sformułowanym kodem inicjującym
Rob11311
memset () może pomóc, ale zależy od wartości.
Nick
2
memset()konkretna dyskusja: stackoverflow.com/questions/7202411/ ... Myślę, że to działa tylko dla 0.
Ciro Santilli 冠状 病毒 审查 六四 事件 法轮功

Odpowiedzi:

1238

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:

int myArray[10] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 };

Elementy z brakującymi wartościami zostaną zainicjowane na 0:

int myArray[10] = { 1, 2 }; // initialize to 1,2,0,0,0...

To zainicjuje wszystkie elementy do 0:

int myArray[10] = { 0 }; // all elements 0

W C ++ pusta lista inicjalizacji również inicjuje każdy element na 0. Nie jest to dozwolone w C:

int myArray[10] = {}; // all elements 0 in C++

Pamiętaj, że obiekty ze statycznym czasem przechowywania będą inicjowane na 0, jeśli nie zostanie określony inicjator:

static int myArray[10]; // all elements 0

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.)

aib
źródło
27
Czytając standard C ++, możesz także wykonać int array [10] = {}; zerować inicjalizację. Nie mam jednak standardu C, aby sprawdzić, czy jest to również poprawne C.
workmad3
54
Patrząc na rozdział 6.7.8 Inicjalizacja standardu C99, nie wydaje się, aby dozwolona była pusta lista inicjalizacyjna.
Jonathan Leffler
7
C99 ma wiele fajnych funkcji do inicjalizacji struktury i tablicy; jedna funkcja, której nie ma (ale miała Fortran IV, 1966), to sposób na powtórzenie określonego inicjalizatora dla tablicy.
Jonathan Leffler
8
@CetinSert: Co masz na myśli mówiąc, że to nie działa? Robi dokładnie to, co mówi ta odpowiedź. Nie robi tego, co mówi komentarz w twoim kodzie, ale ten komentarz jest zły.
Benjamin Lindley,
9
@CetinSert: Jesteś jedynym, który twierdził w tym komentarzu, że wszystkie elementy zostaną ustawione na -1. Ta odpowiedź słusznie twierdzi, że wszystkie nieokreślone elementy zostają ustawione na zero. Wyniki Twojego kodu są zgodne z tym twierdzeniem.
Benjamin Lindley,
394

Jeśli twoim kompilatorem jest GCC, możesz użyć następującej składni:

int array[1024] = {[0 ... 1023] = 5};

Sprawdź szczegółowy opis: http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Designated-Inits.html

qrdl
źródło
12
Ta składnia powoduje ogromny wzrost rozmiaru skompilowanych plików binarnych. Dla N = 65536 (zamiast 1024) mój plik binarny przeskakuje z 15 KB do 270 KB!
Cetin Sert
50
@CetinSert Compiler musi dodać 65536 ints do danych statycznych, czyli 256 K - dokładnie taki wzrost, jaki zaobserwowałeś.
qrdl
15
@CetinSert Dlaczego powinienem? Jest to standardowe zachowanie kompilatora, niespecyficzne dla wyznaczonych inicjatorów. Jeśli zainicjujesz statycznie 65536 ints, int foo1 = 1, foo2 = 1, ..., foo65536 =1;otrzymasz taki sam wzrost rozmiaru.
qrdl
27
jeszcze lepiej: „int array [] = {[0 ... 1023] = 5}”, rozmiar tablicy zostanie automatycznie ustawiony na 1024, łatwiej i bezpieczniej zmodyfikować.
Francois,
4
@Francois lub tablica 2d bool array[][COLS] = { [0...ROWS-1][0...COLS-1] = true}, choć nie jestem pewien, czy jest to bardziej czytelne niż pełna forma.
g33kz0r
178

Do statycznego inicjowania dużej tablicy o tej samej wartości, bez wielokrotnego wklejania i kopiowania, możesz użyć makr:

#define VAL_1X     42
#define VAL_2X     VAL_1X,  VAL_1X
#define VAL_4X     VAL_2X,  VAL_2X
#define VAL_8X     VAL_4X,  VAL_4X
#define VAL_16X    VAL_8X,  VAL_8X
#define VAL_32X    VAL_16X, VAL_16X
#define VAL_64X    VAL_32X, VAL_32X

int myArray[53] = { VAL_32X, VAL_16X, VAL_4X, VAL_1X };

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ą:

#define VAL_1(X) X
#define VAL_2(X) VAL_1(X), VAL_1(X)
/* etc. */

Wariant można utworzyć za pomocą:

#define STRUCTVAL_1(...) { __VA_ARGS__ }
#define STRUCTVAL_2(...) STRUCTVAL_1(__VA_ARGS__), STRUCTVAL_1(__VA_ARGS__)
/*etc */ 

który działa ze strukturami lub tablicami złożonymi.

#define STRUCTVAL_48(...) STRUCTVAL_32(__VA_ARGS__), STRUCTVAL_16(__VA_ARGS__)

struct Pair { char key[16]; char val[32]; };
struct Pair p_data[] = { STRUCTVAL_48("Key", "Value") };
int a_data[][4] = { STRUCTVAL_48(12, 19, 23, 37) };

nazwy makr podlegają negocjacji.

mouviciel
źródło
12
Rozważałbym to tylko w skrajnych przypadkach, z pewnością zestaw memów jest bardziej eleganckim sposobem na wyrażenie tego.
u0b34a0f6ae
47
Jeśli dane muszą obsługiwać pamięć ROM, nie można użyć memset.
Umowa prof. Falkena została naruszona
9
Preprocesor faktycznie wygeneruje kod z #defines. Przy większych wymiarach tablicy rozmiar pliku wykonywalnego wzrośnie. Ale zdecydowanie + za pomysł;)
Leonid
7
@Alcott, na starych komputerach i wciąż na wielu systemach wbudowanych, kod jest ostatecznie umieszczany w EPROM lub ROM . Pamięć ROM może również oznaczać, w systemach wbudowanych, „kod wprowadzony we flashu”, ponieważ ma on te same implikacje, mianowicie, że pamięci nie można zapisać w środowisku wykonawczym. Nie można użyć zestawu memów ani żadnej innej instrukcji aktualizacji lub zmiany pamięci. Jednak stałe mogą być wyrażane i błyskane lub zapisywane w pamięci ROM przed uruchomieniem programu.
Umowa prof. Falkena została naruszona
4
@ u0b34a0f6ae: Pamiętaj, że możesz użyć tej metody również, jeśli VAL_1Xnie 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().
Martin Scharrer
63

Jeśli chcesz się upewnić, że każdy element tablicy jest jawnie zainicjowany, po prostu pomiń wymiar z deklaracji:

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

Kompilator wydedukuje wymiar z listy inicjalizatora. Niestety w przypadku tablic wielowymiarowych można pominąć tylko wymiar zewnętrzny:

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

jest OK, ale

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

nie jest.

Frank Szczerba
źródło
czy to jest poprawne ? int myPoints[10][] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9} };
Praveen Gowda IV,
10
Nie. Pomijasz najbardziej wewnętrzny wymiar, który jest niedozwolony. To spowoduje błąd kompilatora.
Frank Szczerba,
4
Zarówno inicjalizatory, jak i wnioskowanie o długości zostały wprowadzone w C99.
Palec
3
@Palec: Nie - wnioskowanie o długości jest w C od czasów pre-standardowego C (od czasu wydania pierwszej edycji K&R i prawdopodobnie jeszcze chwilę wcześniej). Wyznaczone inicjalizatory były nowe w C99, ale nie korzysta z wyznaczonych inicjatorów.
Jonathan Leffler
53

Widziałem kod korzystający z tej składni:

char* array[] = 
{
    [0] = "Hello",
    [1] = "World"
};   

Szczególnie przydatna jest sytuacja, gdy tworzysz tablicę, która używa indeksu jako indeksu:

enum
{
    ERR_OK,
    ERR_FAIL,
    ERR_MEMORY
};

#define _ITEM(x) [x] = #x

char* array[] = 
{
    _ITEM(ERR_OK),
    _ITEM(ERR_FAIL),
    _ITEM(ERR_MEMORY)
};   

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 .

Abelenky
źródło
8
Jest to składnia inicjalizująca C99, opisana już w niektórych innych odpowiedziach. Mógłbyś z powodzeniem zrobić deklarację, char const *array[] = { ... };a nawet char const * const array[] = { ... };, prawda?
Jonathan Leffler
22
int i;
for (i = 0; i < ARRAY_SIZE; ++i)
{
  myArray[i] = VALUE;
}

Myślę, że to jest lepsze niż

int myArray[10] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5...

zwiększyć wielkość zmian tablicy.

Tarski
źródło
12
Dla przypomnienia, jest to po prostu wolniejsza, bardziej wyczerpująca wersjamemset(myArray, VALUE, ARRAY_SIZE);
Benson
18
Jak użyłbyś zestawu pamięci do zainicjowania tablicy int do wartości większej niż 255? memset działa tylko wtedy, gdy tablica ma rozmiar bajtu.
Matt
21
@Benson: Nie możesz zastąpić powyższego kodu zestawem na platformach, na których sizeof (int)> sizeof (char). Spróbuj.
ChrisWue,
13

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.

cokół
źródło
Czy mógłbyś dodać przykład użycia tej metody memsetinicjalizacji tablicy?
Sopalajo de Arrierez
8

Oto inny sposób:

static void
unhandled_interrupt(struct trap_frame *frame, int irq, void *arg)
{
    //this code intentionally left blank
}

static struct irqtbl_s vector_tbl[XCHAL_NUM_INTERRUPTS] = {
    [0 ... XCHAL_NUM_INTERRUPTS-1] {unhandled_interrupt, NULL},
};

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.

humble_guru
źródło
6

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:

// put values 1-8, then two zeroes
int list[10] = {1,2,3,4,5,6,7,8};
królikarnia
źródło
5

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.

ddimitrow
źródło
5

Lekko wymowna odpowiedź; napisz oświadczenie

array = initial_value

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ą.

Znak wysokiej wydajności
źródło
4

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:

  • zainicjuj pierwszy element tablicy (zwykły sposób)
  • kopiuj część, która została ustawiona na część, która nie została ustawiona, podwajając rozmiar przy każdej kolejnej operacji kopiowania

W przypadku tablicy 1 000 000elementów intjest 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]


#include <stdio.h>
#include <time.h>
#include <string.h>
#define ARR_SIZE 1000000

void memfill(void *dest, size_t destsize, size_t elemsize) {
   char   *nextdest = (char *) dest + elemsize;
   size_t movesize, donesize = elemsize;

   destsize -= elemsize;
   while (destsize) {
      movesize = (donesize < destsize) ? donesize : destsize;
      memcpy(nextdest, dest, movesize);
      nextdest += movesize; destsize -= movesize; donesize += movesize;
   }
}    
int main() {
    clock_t timeStart;
    double  runTime;
    int     i, a[ARR_SIZE];

    timeStart = clock();
    for (i = 0; i < ARR_SIZE; i++)
        a[i] = 9;    
    runTime = (double)(clock() - timeStart) / (double)CLOCKS_PER_SEC;
    printf("loop runtime %f [seconds]\n",runTime);

    timeStart = clock();
    a[0] = 10;
    memfill(a, sizeof(a), sizeof(a[0]));
    runTime = (double)(clock() - timeStart) / (double)CLOCKS_PER_SEC;
    printf("memfill() runtime %f [seconds]\n",runTime);
    return 0;
}
Maciej
źródło
2
Przepraszam, ale to nieprawda. Być może zapomniałeś włączyć optymalizację kompilacji podczas testów (testowane w trybie debugowania?). Jeśli to przetestuję, pętla jest prawie zawsze o 50% szybsza niż memfill („zawsze” z powodu pewnych drgań obciążenia na moim komputerze). I używając memset (a, 0, sizeof (a)); jest nawet dwa razy szybszy niż loopfill.
RS1980
2
Podobnie jak w przypadku każdego kodu porównawczego, musisz być bardzo ostrożny. Dodanie pętli w celu wykonania kodu czasowego 10 razy (i podwojenie rozmiaru tablicy do 20M) pokazuje - dla mnie, uruchamianie na MacBooku Pro z macOS Sierra 10.12.3 i używanie GCC 6.3.0 - że po raz pierwszy, używając pętla zajmuje około 4600 µs, podczas gdy memfill()kod zajmuje około 1200 µs. Jednak podczas kolejnych iteracji pętla zajmuje około 900-1000 µs, podczas gdy memfill()kod zajmuje 1000-1300 µs. Prawdopodobnie na pierwszą iterację ma czas wypełnienia pamięci podręcznej. Odwróć testy i memfill()po raz pierwszy jest wolny.
Jonathan Leffler
2

Nikt nie wspomniał o indeksie dostępu do elementów zainicjowanej tablicy. Mój przykładowy kod da przykładowy przykład.

#include <iostream>

void PrintArray(int a[3][3])
{
    std::cout << "a11 = " << a[0][0] << "\t\t" << "a12 = " << a[0][1] << "\t\t" << "a13 = " << a[0][2] << std::endl;
    std::cout << "a21 = " << a[1][0] << "\t\t" << "a22 = " << a[1][1] << "\t\t" << "a23 = " << a[1][2] << std::endl;
    std::cout << "a31 = " << a[2][0] << "\t\t" << "a32 = " << a[2][1] << "\t\t" << "a33 = " << a[2][2] << std::endl;
    std::cout << std::endl;
}

int wmain(int argc, wchar_t * argv[])
{
    int a1[3][3] =  {   11,     12,     13,     // The most
                        21,     22,     23,     // basic
                        31,     32,     33  };  // format.

    int a2[][3] =   {   11,     12,     13,     // The first (outer) dimension
                        21,     22,     23,     // may be omitted. The compiler
                        31,     32,     33  };  // will automatically deduce it.

    int a3[3][3] =  {   {11,    12,     13},    // The elements of each
                        {21,    22,     23},    // second (inner) dimension
                        {31,    32,     33} };  // can be grouped together.

    int a4[][3] =   {   {11,    12,     13},    // Again, the first dimension
                        {21,    22,     23},    // can be omitted when the 
                        {31,    32,     33} };  // inner elements are grouped.

    PrintArray(a1);
    PrintArray(a2);
    PrintArray(a3);
    PrintArray(a4);

    // This part shows in which order the elements are stored in the memory.
    int * b = (int *) a1;   // The output is the same for the all four arrays.
    for (int i=0; i<9; i++)
    {
        std::cout << b[i] << '\t';
    }

    return 0;
}

Dane wyjściowe to:

a11 = 11                a12 = 12                a13 = 13
a21 = 21                a22 = 22                a23 = 23
a31 = 31                a32 = 32                a33 = 33

a11 = 11                a12 = 12                a13 = 13
a21 = 21                a22 = 22                a23 = 23
a31 = 31                a32 = 32                a33 = 33

a11 = 11                a12 = 12                a13 = 13
a21 = 21                a22 = 22                a23 = 23
a31 = 31                a32 = 32                a33 = 33

a11 = 11                a12 = 12                a13 = 13
a21 = 21                a22 = 22                a23 = 23
a31 = 31                a32 = 32                a33 = 33

11      12      13      21      22      23      31      32      33
hkBattousai
źródło
4
<iostream>Nie jest ważne Cjak std::cout, std::cinitp jest częścią std::namespacei Cnie obsługuje namespaces. Spróbuj użyć <stdio.h>do printf(...)zamiast.
Francis Cugler,
2

Przeglądając całą paplaninę, krótka odpowiedź brzmi: jeśli włączysz optymalizację w czasie kompilacji, nie zrobisz nic lepszego:

int i,value=5,array[1000]; 
for(i=0;i<1000;i++) array[i]=value; 

Dodano bonus: kod jest czytelny :)

JWDN
źródło
7
Pytanie konkretnie zadane do inicjalizacji. Nie jest to wyraźnie inicjalizacja, ale przypisanie wykonane po inicjalizacji. Można to zrobić natychmiast, ale nadal nie jest to inicjalizacja.
Andy,
Całkowicie nieprzydatne w przypadku dużej statycznej tabeli odnośników wewnątrz funkcji wywoływanej wiele razy.
Martin Bonner wspiera Monikę
... nie przypominaj sobie statycznych tabel wyszukiwania wewnątrz funkcji będących częścią pierwotnego pytania - zachowaj prostotę. To powiedziawszy, @Community prawdopodobnie go przybili.
JWDN
1
  1. Jeśli tablica jest zadeklarowana jako statyczna lub globalna, wszystkie elementy w tablicy mają już domyślną wartość domyślną 0.
  2. Niektóre kompilatory ustawiają domyślną tablicę na 0 w trybie debugowania.
  3. Łatwo jest ustawić wartość domyślną na 0: int array [10] = {0};
  4. Jednak w przypadku innych wartości używasz memset () lub pętli;

przykład: int array [10]; memset (tablica, -1, 10 * sizeof (int));

Hannah Zhang
źródło
0
#include<stdio.h>
int main(){
int i,a[50];
for (i=0;i<50;i++){
    a[i]=5;// set value 5 to all the array index
}
for (i=0;i<50;i++)
printf("%d\n",a[i]);
   return 0;
}

Daje o / p 5 5 5 5 5 5 ...... aż do wielkości całej tablicy

Dadhich Sourav
źródło
0

Wiem, że użytkownik Tarskiodpowiedział 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 ...

#include <stdio.h>

typedef const unsigned int cUINT;
typedef unsigned int UINT;

cUINT size = 10;
cUINT initVal = 5;

void arrayInitializer( UINT* myArray, cUINT size, cUINT initVal );
void printArray( UINT* myArray ); 

int main() {        
    UINT myArray[size]; 
    /* Not initialized during declaration but can be
    initialized using a function for the appropriate TYPE*/
    arrayInitializer( myArray, size, initVal );

    printArray( myArray );

    return 0;
}

void arrayInitializer( UINT* myArray, cUINT size, cUINT initVal ) {
    for ( UINT n = 0; n < size; n++ ) {
        myArray[n] = initVal;
    }
}

void printArray( UINT* myArray ) {
    printf( "myArray = { " );
    for ( UINT n = 0; n < size; n++ ) {
        printf( "%u", myArray[n] );

        if ( n < size-1 )
            printf( ", " );
    }
    printf( " }\n" );
}

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 functiondla każdego typeobsł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 .

Francis Cugler
źródło
0

W przypadku opóźnionej inicjalizacji (tj. Inicjalizacji konstruktora elementu klasy) należy rozważyć:

int a[4];

unsigned int size = sizeof(a) / sizeof(a[0]);
for (unsigned int i = 0; i < size; i++)
  a[i] = 0;
nikc
źródło
0

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_sequencewygenerować listę inicjalizującą z żądaną wartością. Możesz to wyrównać constexpri poczuć się jak szef:

#include <array>

/// [3]
/// This functions's only purpose is to ignore the index given as the second
/// template argument and to always produce the value passed in.
template<class T, size_t /*ignored*/>
constexpr T identity_func(const T& value) {
    return value;
}

/// [2]
/// At this point, we have a list of indices that we can unfold
/// into an initializer list using the `identity_func` above.
template<class T, size_t... Indices>
constexpr std::array<T, sizeof...(Indices)>
make_array_of_impl(const T& value, std::index_sequence<Indices...>) {
    return {identity_func<T, Indices>(value)...};
}

/// [1]
/// This is the user-facing function.
/// The template arguments are swapped compared to the order used
/// for std::array, this way we can let the compiler infer the type
/// from the given value but still define it explicitly if we want to.
template<size_t Size, class T>
constexpr std::array<T, Size> 
make_array_of(const T& value) {
    using Indices = std::make_index_sequence<Size>;
    return make_array_of_impl(value, Indices{});
}

// std::array<int, 4>{42, 42, 42, 42}
constexpr auto test_array = make_array_of<4/*, int*/>(42);
static_assert(test_array[0] == 42);
static_assert(test_array[1] == 42);
static_assert(test_array[2] == 42);
static_assert(test_array[3] == 42);
// static_assert(test_array[4] == 42); out of bounds

Możesz rzucić okiem na kod w pracy (w Wandbox)

Clemens Sielaff
źródło
-1

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:

#include <string.h> 

void array_init( void *start, size_t element_size, size_t elements, void *initval ){
  memcpy(        start,              initval, element_size              );
  memcpy( (char*)start+element_size, start,   element_size*(elements-1) );
}

// testing
#include <stdio.h> 

struct s {
  int a;
  char b;
} array[2][3], init;

int main(){
  init = (struct s){.a = 3, .b = 'x'};
  array_init( array, sizeof(array[0][0]), 2*3, &init );

  for( int i=0; i<2; i++ )
    for( int j=0; j<3; j++ )
      printf("array[%i][%i].a = %i .b = '%c'\n",i,j,array[i][j].a,array[i][j].b);
}

Wynik:

array[0][0].a = 3 .b = 'x'
array[0][1].a = 3 .b = 'x'
array[0][2].a = 3 .b = 'x'
array[1][0].a = 3 .b = 'x'
array[1][1].a = 3 .b = 'x'
array[1][2].a = 3 .b = 'x'

EDYCJA: start+element_sizezmieniona na(char*)start+element_size

sambowry
źródło
1
Mam wątpliwości, czy to rozwiązanie. Nie jestem pewien, czy w sizeof(void)ogóle jest ważny.
Chris Lutz
3
To nie działa Tylko pierwsze dwa są inicjowane, pozostałe są niezainicjowane. Używam GCC 4.0 na Mac OS X 10.4.
dreamlax
Wywołuje to niezdefiniowane zachowanie, ponieważ dane źródłowe w drugiej części memcpy()pokrywają się z miejscem docelowym. Przy naiwnym wdrożeniu memcpy()może działać, ale system nie wymaga, aby działał.
Jonathan Leffler
-1

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.

Mikrofon
źródło
To nie zadziała niezawodnie. IMHO, Standard powinien był zapewnić funkcje, które były podobne, memcpyale 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.
supercat
Jak powiedziałem, było to po prostu coś, co zrobiliśmy, co nie działałoby niezawodnie, ale wtedy bardziej skupialiśmy się na wydajności niż unikaniu nieudokumentowanych funkcji. Chociaż bardziej wydajne jest kopiowanie pamięci do przodu, w specyfikacji nie ma nic, co by mówiło, że nie można jej skopiować do tyłu, w losowej kolejności ani podzielić na wiele wątków. memmove () zapewnia możliwość kopiowania bez kolizji.
Mike
Jest to równoważne kodowi w innej odpowiedzi - i jest wadliwe. Korzystanie memmove()nie działa.
Jonathan Leffler
-2

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ć:

a[1]=1, a[2]=2, ..., a[indexSize]; 

lub jeśli masz na myśli jedną konstrukcję, możesz to zrobić w pętli for:

for(int index = 0, value = 10; index < sizeof(array)/sizeof(array[0]); index++, value--)
  array[index] = index;

// Uwaga: przecinek na liście argumentów nie jest operatorem równoległym opisanym powyżej;

Możesz zainicjować deklinację tablicy:

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

Możesz zadzwonić do malloc / calloc / sbrk / przydzielać / etc, aby przydzielić ustalony region pamięci do obiektu:

int *array = malloc(sizeof(int)*numberOfListElements/Indexes);

i uzyskać dostęp do członków przez:

*(array + index)

Itp.

pchelper4
źródło
Operator przecinka nominalnie gwarantuje ocenę od lewej do prawej. Jeśli w wyrażeniach nie ma efektów ubocznych, może być możliwe zrównoleglenie operacji, ale kompilator by to zrobił.
Jonathan Leffler