Bir dizinin tüm üyelerini aynı değere nasıl başlatabilirim?


968

C ( bir fark yaparsa değil C ++) büyük bir dizi var . Aynı değere sahip tüm üyeleri başlatmak istiyorum.

Yemin edebilirim ki bir keresinde bunu yapmanın basit bir yolunu biliyordum. memset()Benim durumumda kullanabilirsiniz , ama bunu doğrudan C sözdizimi içine yerleşik bir yolu yok mu?


16
Şimdiye kadar cevapların hiçbiri, C99 ve üstü ile mümkün olan belirlenmiş başlatıcı göstergesinden bahsetmiyor. Örneğin: enum { HYDROGEN = 1, HELIUM = 2, CARBON = 6, NEON = 10, … };ve struct element { char name[15]; char symbol[3]; } elements[] = { [NEON] = { "Neon", "Ne" }, [HELIUM] = { "Helium", "He" }, [HYDROGEN] = { "Hydrogen", "H" }, [CARBON] = { "Carbon", "C" }, … };. Üç nokta çıkarılırsa , bu parçalar C99 veya C11 altında derlenir.
Jonathan Leffler

Aslında abelenky'nin cevabı belirlenmiş başlatıcı kullanıyor, ancak tam olarak başlatılmamış kod oluşturulmuyor
Rob11311

memset () yardımcı olabilir, ancak değere bağlıdır.
Nick

2
memset()özel tartışma: stackoverflow.com/questions/7202411/… Bence sadece 0 için çalışıyor.
Ciro Santilli 法轮功 病毒 审查 六四 事件 法轮功

Yanıtlar:


1239

Bu değer 0 olmadığı sürece (bu durumda başlatıcı parçasının bir kısmını atlayabilirsiniz ve karşılık gelen öğeler 0 olarak başlatılır), kolay bir yol yoktur.

Bununla birlikte, bariz çözümü göz ardı etmeyin:

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

Eksik değerleri olan öğeler 0 olarak başlatılır:

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

Böylece bu, tüm öğeleri 0 olarak başlatır:

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

C ++ 'da, boş bir başlatma listesi her öğeyi 0 olarak başlatır. Buna C ile izin verilmez :

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

Başlatıcı belirtilmezse statik depolama süresine sahip nesnelerin 0 olarak başlayacağını unutmayın:

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

Ve bu "0" mutlaka "all-bit-zero" anlamına gelmez, bu nedenle yukarıdakileri kullanmak memset () 'den daha iyi ve daha taşınabilirdir. (Kayan nokta değerleri +0, işaretçiler boş değere vb. Olarak başlatılacaktır.)


27
C ++ standardını kullanarak, int array [10] = {}; sıfıra sıfırlamak. Ben de geçerli C olup olmadığını kontrol etmek için C standardı yok.
workmad3

54
6.7.8 C99 standardının başlatılması bölümüne bakıldığında, boş bir başlatma listesine izin verildiği görülmemektedir.
Jonathan Leffler

7
C99, yapı ve dizi başlatma için birçok güzel özelliğe sahiptir; sahip olmadığı bir özellik (ancak Fortran IV, 1966, sahip olduğu) bir dizi için belirli bir başlatıcıyı tekrarlamanın bir yoludur.
Jonathan Leffler

8
@CetinSert: Ne demek çalışmıyor? Bu cevabın yapması gereken şeyi tam olarak yapar. Kodunuzdaki yorumun söylediği şeyi yapmaz, ancak bu yorum yanlıştır.
Benjamin Lindley

9
@CetinSert: Bu yorumda tüm öğelerin -1 olarak ayarlanacağını iddia eden tek kişi sensin. Bu cevap, haklı olarak, belirtilmemiş tüm elemanların sıfıra ayarlandığını iddia ediyor. Kodunuzun sonuçları bu talebe uygundur.
Benjamin Lindley

394

Derleyiciniz GCC ise, aşağıdaki sözdizimini kullanabilirsiniz:

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

Ayrıntılı açıklamaya göz atın: http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Designated-Inits.html


12
Ve bu sözdizimi, derlenmiş ikili dosyaların dosya boyutunda büyük bir artışa neden olur. N = 65536 (1024 yerine) için, ikili dosyam boyutu 15 KB'tan 270 KB'ye atlıyor!
Çetin Sert

50
@CetinSert Compiler int, 256 K olan statik verilere 65536 s eklemelidir - tam olarak gözlemlediğiniz boyut artışı.
2013

15
@CetinSert Neden yapayım? Belirtilen başlatıcılar için spesifik olmayan standart bir derleyici davranışıdır. Statik olarak 65536 ints'yi başlatırsanız int foo1 = 1, foo2 = 1, ..., foo65536 =1;, aynı boyut artışını elde edersiniz.
2013

27
daha iyisi: "int dizi [] = {[0 ... 1023] = 5}", dizinin boyutu otomatik olarak 1024 olarak ayarlanacak, değiştirilmesi daha kolay ve daha güvenli olacaktır.
Francois

4
@Francois veya 2d dizi için, bool array[][COLS] = { [0...ROWS-1][0...COLS-1] = true}bunun tam formdan daha okunabilir olduğundan emin değilim.
g33kz0r

178

Birden çok kopyala yapıştır olmadan aynı değere sahip büyük bir diziyi statik olarak başlatmak için makroları kullanabilirsiniz:

#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 };

Değeri değiştirmeniz gerekirse, değiştirme işlemini tek bir yerde yapmanız gerekir.

Düzenleme: olası yararlı uzantılar

( Jonathan Leffler'ın izniyle )

Bunu aşağıdakilerle kolayca genelleştirebilirsiniz:

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

Bir değişken aşağıdakiler kullanılarak oluşturulabilir:

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

yapılar veya bileşik dizilerle çalışır.

#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) };

makro isimleri tartışılabilir.


12
Bunu sadece aşırı durumlarda düşünürdüm, elbette bir memset bunu ifade etmenin daha zarif bir yoludur.
u0b34a0f6ae

47
Verilerin ROM kullanabilmesi gerekiyorsa, memset kullanılamaz.
Prof. Falken sözleşmesi

9
Önişlemci kodu #defines'den oluşturur. Daha büyük dizi boyutları ile yürütülebilir boyut büyür. Ama kesinlikle + fikir için;)
Leonid

7
@Alcott, eski bilgisayarlarda ve hala birçok gömülü sistemde, kod sonunda bir EPROM veya ROM'a yerleştirilir . ROM-mümkün olan, gömülü sistemlerde, "flash koymak kodu" anlamına da gelmiştir, çünkü yaklaşık olarak aynı sonuçları vardır, yani bellek çalışma zamanı yazılamaz. Yani memset veya hafızayı güncellemek veya değiştirmek için başka herhangi bir talimat kullanılamaz. Ancak sabitler, program başlamadan önce ifade edilebilir ve yanıp sönebilir veya ROM ile düzenlenebilir.
Prof. Falken sözleşmesi

4
@ u0b34a0f6ae: VAL_1XTek bir tam sayı değil, bir liste de olsa bu yöntemi kullanabileceğinizi unutmayın . Uygun Durumlar gibi, bu aynı zamanda bir EEPROM veya Flash belleğin başlangıç ​​değerlerini tanımlamak istediğiniz gömülü sistemler için de kullanılabilir. Her iki durumda da kullanamazsınız memset().
Martin Scharrer

63

Dizinin her üyesinin açıkça başlatılmasını sağlamak istiyorsanız, boyutu bildirimden çıkarmanız yeterlidir:

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

Derleyici boyutu başlatıcı listesinden çıkarır. Ne yazık ki, çok boyutlu diziler için yalnızca en dıştaki boyut göz ardı edilebilir:

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

tamam, ama

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

değil.


bu doğru mu ? int myPoints[10][] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9} };
Praveen Gowda IV

10
Hayır. İzin verilmeyen en içteki boyutu atlıyorsunuz. Bu bir derleyici hatası verecektir.
Frank Szczerba

4
Hem başlatıcılar hem de uzunluk çıkarımları C99'da tanıtıldı.
Palec

3
@Palec: Standart öncesi C günlerinden bu yana C'de uzunluğunda çıkarım (K&R 1st Edition yayınlandığından beri ve muhtemelen bir süre önce). Belirtilen başlatıcılar C99'da yeniydi, ancak bu belirtilen başlatıcıları kullanmıyor.
Jonathan Leffler

53

Bu sözdizimini kullanan bazı kodlar gördüm:

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

Özellikle kullanışlı hale geldiği nokta, dizin olarak numaralandırmalar kullanan bir dizi oluşturuyorsanız:

enum
{
    ERR_OK,
    ERR_FAIL,
    ERR_MEMORY
};

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

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

Bu, enum-değerlerinden bazılarını düzensiz yazsanız bile işleri düzenli tutar.

Bu teknik hakkında daha fazla bilgiyi burada ve burada bulabilirsiniz .


8
Bu, diğer cevapların bir kısmı tarafından zaten kapsanan C99 başlatıcısı sözdizimidir. Beyanı faydalı bir şekilde yapabilirsin, char const *array[] = { ... };hatta char const * const array[] = { ... };yapamazdın, değil mi?
Jonathan Leffler

22
int i;
for (i = 0; i < ARRAY_SIZE; ++i)
{
  myArray[i] = VALUE;
}

Bence bu daha iyi

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

dizinin boyutu değiştiğinde.


12
Kayıt için, bu sadece daha yavaş, daha ayrıntılı bir versiyonmemset(myArray, VALUE, ARRAY_SIZE);
Benson

18
Bir int dizisini 255'ten büyük bir değere başlatmak için memset'i nasıl kullanırsınız? memset yalnızca dizi bayt boyutundaysa çalışır.
Matt

21
@Benson: Yukarıdaki kodu sizeof (int)> sizeof (char) olan platformlarda memset ile değiştiremezsiniz. Dene.
ChrisWue

13

Tüm statik başlatıcı işlemini yukarıda açıklandığı gibi yapabilirsiniz, ancak dizi boyutunuz değiştiğinde gerçek bir serseri olabilir (diziniz embiggens olduğunda, uygun ekstra başlatıcıları eklemezseniz çöp alırsınız).

memset, işi yapmak için size bir çalışma zamanı isabeti verir, ancak doğru yapılan hiçbir kod boyutu isabeti dizi boyutu değişikliklerinden etkilenmez. Bu çözümü, dizinin birkaç düzine öğeden daha büyük olduğu hemen hemen tüm durumlarda kullanırım.

Dizinin statik olarak bildirilmesi gerçekten önemliyse, programı benim için yazmak ve oluşturma işleminin bir parçası yapmak için bir program yazardım.


memsetDiziyi başlatmak için bu kullanımına bir örnek ekleyebilir misiniz ?
Sopalajo de Arrierez

8

İşte başka bir yol:

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},
};

Görmek:

C-Uzantıları

Belirlenmiş başlangıçlar

O zaman şu soruyu sorun: Biri ne zaman C uzantılarını kullanabilir?

Yukarıdaki kod örneği gömülü bir sistemdedir ve asla başka bir derleyiciden gelen ışığı görmez.


6

'Normal' veri türlerini (int dizileri gibi) başlatmak için köşeli ayraç gösterimini kullanabilirsiniz, ancak dizide hala boşluk varsa sondan sonraki değerleri sıfırlar:

// put values 1-8, then two zeroes
int list[10] = {1,2,3,4,5,6,7,8};

5

Dizi int veya int büyüklüğünde bir şey varsa veya mem-deseninizin boyutu tam olarak bir int'e (yani tüm sıfırlar veya 0xA5A5A5A5) uyuyorsa, en iyi yol memset () kullanmaktır .

Aksi takdirde, dizini hareket ettiren bir döngüde memcpy () yöntemini çağırın.


5

Hafifçe yanaktan cevap; ifadeyi yaz

array = initial_value

En sevdiğiniz dizi özellikli dilde (benimki Fortran, ancak diğerleri var) ve onu C kodunuza bağlayın. Muhtemelen harici bir işlev olarak sarmak istersiniz.


4

Herhangi bir türde diziyi verilen değerle başlatmanın hızlı bir yolu vardır. Büyük dizilerle çok iyi çalışır. Algoritma aşağıdaki gibidir:

  • dizinin ilk öğesini başlat (normal yolla)
  • ayarlanmamış parçaya yerleştirilmiş kopya parçası, sonraki her kopya işleminde boyut iki katına çıkar

İçin 1 000 000elemanları intdizisi düzenli çevrim başlatma (i5, 2 çekirdek, 2.3 GHz 4GiB belleği 64 bit) daha hızlı 4 kat:

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;
}

2
Üzgünüm, ama bu doğru değil. Testleriniz sırasında derleme optimizasyonunu açmayı unutmuş olabilirsiniz (hata ayıklama modu ile test edildi?). Bunu test edersem, döngü neredeyse her zaman memfill'den% 50 daha hızlıdır (makinemdeki bazı yük titremeleri nedeniyle 'her zaman'). Ve memset (a, 0, sizeof (a)) kullanarak; döngü dolgusundan iki kat daha hızlıdır.
RS1980

2
Herhangi bir kıyaslama kodunda olduğu gibi, son derece dikkatli olmanız gerekir. Zamanlama kodunu 10 kez yürütmek için bir döngü eklemek (ve dizinin boyutunu 20M'ye ikiye katlamak) - benim için, macOS Sierra 10.12.3 ile bir MacBook Pro'da çalışıyor ve GCC 6.3.0'ı kullanıyor - ilk kez döngü yaklaşık 4600 µs alırken, memfill()kod yaklaşık 1200 µs alır. Bununla birlikte, daha sonraki yinelemelerde, memfill()kod 1000-1300 µs alırken, döngü yaklaşık 900-1000 µs alır. İlk yineleme büyük olasılıkla önbelleği doldurma süresinden etkilenir. Testleri tersine çevirin ve memfill()ilk kez yavaşlayın.
Jonathan Leffler

2

Başlatılan dizinin öğelerine erişmek için dizin sırasından kimse söz etmedi. Örnek kodum buna açıklayıcı bir örnek verecektir.

#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;
}

Çıktı:

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

4
<iostream>geçerli değil Colarak std::cout, std::cinvb parçasıdır std::namespaceve Cdesteklemez namespaces. Kullanmayı deneyin <stdio.h>için printf(...)yerine.
Francis Cugler

2

Tüm konuşmaları keserken, kısa cevap şudur: Derleme zamanında optimizasyonu açarsanız bundan daha iyisini yapamazsınız:

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

Ek bonus: kod aslında okunaklı :)


7
Soru özellikle başlatılmasını istedi. Bu açıkça başlatma değil, başlatmadan sonra atama yapılır . Hemen yapılabilir, ancak yine de başlatma değildir.
Andy

Birçok kez denilen bir işlev içinde büyük bir statik arama tablosu için tamamen yararlı değildir.
Martin Bonner

... orijinal sorunun bir parçası olan fonksiyonların içindeki statik arama tablolarını hatırlamayın - basit tutun. Bununla birlikte, @Topluluk muhtemelen çivilenmişti.
JWDN

1
  1. Diziniz statik veya genel olarak bildirilirse, dizideki tüm öğelerin zaten varsayılan varsayılan değeri 0'dır.
  2. Bazı derleyiciler hata ayıklama modunda dizinin varsayılan değerini 0 olarak ayarlar.
  3. Varsayılanı 0 olarak ayarlamak kolaydır: int array [10] = {0};
  4. Ancak, diğer değerler için memset () veya loop kullanmanız gerekir;

örnek: int dizi [10]; memset (dizi, -1, 10 * sizeof (int));


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;
}

O / p verecektir 5 5 5 5 5 5 ...... bütün dizi büyüklüğüne kadar


0

Kullanıcının Tarskibu soruyu benzer şekilde yanıtladığını biliyorum , ancak birkaç ayrıntı daha ekledim. C + 'yı kullanmak için daha eğilimli olduğum için biraz paslı olduğum için C'yi biraz bağışlayın, ama işte gidiyor.


Dizinin boyutunu önceden biliyorsanız ...

#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" );
}

Yukarıda birkaç uyarı vardır; birincisi, UINT myArray[size];bildirim üzerine doğrudan başlatılmaz, ancak bir sonraki kod bloğu veya işlev çağrısı dizinin her öğesini istediğiniz değere başlatır. Diğer uyarı, destekleyeceğiniz initializing functionher biri için bir yazmak zorunda typekalacaksınız ve ayrıca printArray()bu türleri desteklemek için işlevi değiştirmeniz gerekecektir .


Bu kodu, burada bulunan çevrimiçi bir karşılaştırıcıyla deneyebilirsiniz .


0

Gecikmeli başlatma (yani, sınıf üyesi yapıcı başlatma) için şunları göz önünde bulundurun:

int a[4];

unsigned int size = sizeof(a) / sizeof(a[0]);
for (unsigned int i = 0; i < size; i++)
  a[i] = 0;

0

Orijinal sorunun açıkça C ++ 'dan bahsetmediğini biliyorum, ancak (benim gibi) buraya C ++ dizileri için bir çözüm aramaya geldiyseniz, işte düzgün bir numara:

Derleyiciniz katlama ifadelerini destekliyorsa , şablon büyüsünü ve std::index_sequenceistediğiniz değere sahip bir başlatıcı listesi oluşturmak için kullanabilirsiniz . Ve bunu bile yapabilir constexprve bir patron gibi hissedebilirsiniz:

#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

Sen bir göz alabilir iş yerinde kod (Wandbox at)


-1

Soruda herhangi bir gereksinim görmüyorum, bu yüzden çözüm genel olmalı: belirtilmemiş, muhtemelen çok boyutlu bir dizinin başlangıç ​​üye değeri olan belirtilmemiş olası yapı elemanlarından başlatılması:

#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);
}

Sonuç:

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'

EDIT: olarak start+element_sizedeğiştirildi(char*)start+element_size


1
Bunun bir çözüm olup olmadığı konusunda şüpheliyim. sizeof(void)Hatta geçerli olup olmadığından emin değilim .
Chris Lutz

3
Çalışmıyor. Sadece ilk ikisi başlatılır, geri kalanı da başlatılmaz. Mac OS X 10.4'te GCC 4.0 kullanıyorum.
dreamlax

Bu, tanımlanmamış davranışı başlatır, çünkü ikinci kaynak veriler memcpy()hedef alanla çakışır. Saf bir uygulama ile memcpy()işe yarayabilir, ancak sistemin çalışması için gerekli değildir.
Jonathan Leffler

-1

Gün içinde (ve bunun iyi bir fikir olduğunu söylemiyorum), ilk öğeyi ayarladıktan sonra:

memcpy (&element [1], &element [0], sizeof (element)-sizeof (element [0]);

Artık (memcpy'nin uygulanmasına bağlı olacak) işe yarayacağından bile emin değilim, ancak ilk öğeyi tekrar tekrar bir sonraki öğeye kopyalayarak çalışır - hatta yapı dizileri için çalışır.


Güvenilir bir şekilde çalışmaz. IMHO, Standart memcpy, çakışma durumunda aşağıdan yukarıya veya yukarıdan aşağıya kopyalama sırası gibi ancak belirtilmemiş işlevler sağlamalıdır .
Supercat

Dediğim gibi, bu güvenilir bir şekilde işe yaramayacak bir şeydi, ancak o zamanlar, belgelenmemiş özelliklerden kaçınmaktan çok verimliliğe odaklandık. Belleği ileri doğru kopyalamak daha verimli olsa da, spesifikasyonda, geriye doğru, rastgele bir sırayla kopyalayamayacağını veya birden fazla iş parçacığına bölemeyeceğini söyleyecek hiçbir şey yoktur. memmove (), çakışma olmadan kopyalama olanağı sağlar.
Mike

Bu, başka bir cevaptaki koda eşdeğerdir - ve kusurludur. Kullanmak memmove()işe yaramaz.
Jonathan Leffler

-2

Paralel demek isterseniz, bir ifadeyle birlikte kullanıldığında virgül operatörü bunu yapabilir:

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

veya tek bir kurgudan kastediyorsanız, bunu bir for döngüsü içinde yapabilirsiniz:

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

// Bağımsız değişkenler listesindeki virgül işlecinin yukarıda açıklanan paralel işleç olmadığını unutmayın;

Bir dizi bildirimi başlatabilirsiniz:

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

Sabit bir depolama bölgesini bir nesneye tahsis etmek için malloc / calloc / sbrk / alloca / etc'ye çağrı yapabilirsiniz:

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

ve üyelere şu yolla erişin:

*(array + index)

Vb.


Virgül operatörü nominal olarak soldan sağa değerlendirmeyi garanti eder. İfadelerde yan etki yoksa, işlemleri paralel hale getirmek mümkün olabilir, ancak bir derleyicinin bunu yapmak olağandışı olacaktır.
Jonathan Leffler
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.