Frage

Ich habe ein großes array in C (nicht C++ ob das einen Unterschied macht).Ich initialisieren möchten alle Mitglieder auf den gleichen Wert.Ich könnte schwören, ich kannte einmal einen einfachen Weg, dies zu tun.Ich könnte verwenden memset() in meinem Fall, aber gibt es nicht eine Möglichkeit, dies zu tun, dass ist gebaut rechts in die C-syntax?

War es hilfreich?

Lösung

Es sei denn, dieser Wert 0 ist (in diesem Fall können Sie einen Teil der initializer auslassen und die entsprechenden Elemente auf 0 initialisiert werden), gibt es keine einfache Möglichkeit.

Sie die offensichtliche Lösung nicht übersehen, aber:

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

Elemente mit fehlenden Werten werden auf 0 initialisiert werden:

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

So werden dadurch alle Elemente auf 0 initialisiert werden:

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

In C ++, eine leere Initialisierungsliste wird auch jedes Element auf 0 initialisiert werden. Dies ist nicht erlaubt mit C:

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

Beachten Sie, dass Objekte mit statischer Speicherdauer auf 0 initialisiert werden, wenn keine Initialisierer angegeben:

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

Und die „0“ bedeutet nicht unbedingt, „All-Bits-Null“, so dass die obigen Verwendung ist besser und mehr tragbar als memset (). (Gleitkomma-Werte zu messen initialisiert +0, Zeiger auf null Wert, etc.)

Andere Tipps

Wenn Ihr Compiler GCC Sie folgende Syntax verwenden:

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

Schauen Sie sich detaillierte Beschreibung: http://gcc.gnu.org/onlinedocs/gcc -4.1.2 / gcc / Designated-Inits.html

Für statisch ein großes Array mit dem gleichen Wert, ohne dass mehrere Copy-Paste-Initialisierung können Sie Makros verwenden:

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

Wenn Sie den Wert ändern, müssen Sie nur an einem Ort, um den Austausch zu tun.

Edit: mögliche nützliche Erweiterungen

(mit freundlicher Genehmigung von Jonathan Leffler )

Sie können dies leicht verallgemeinern mit:

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

Eine Variante kann folgendermaßen angelegt werden:

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

, das funktioniert mit Strukturen oder Verbindung Arrays.

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

Makronamen sind verhandelbar.

Wenn Sie sicherstellen wollen, dass jedes Mitglied des Arrays explizit initialisiert wird, lassen Sie einfach die Dimension aus der Erklärung:

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

Der Compiler wird die Dimension von der Initialisiererliste ableiten. Leider für mehrdimensionale Arrays nur die äußerste Dimension verzichtet werden kann:

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

ist in Ordnung, aber

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

ist es nicht.

sah ich einige Code, der diese Syntax verwendet:

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

Dabei gilt es besonders nützlich wird, wenn Sie eine Reihe stellen, für die Aufzählungen als Index verwendet:

enum
{
    ERR_OK,
    ERR_FAIL,
    ERR_MEMORY
};

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

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

Dies hält die Dinge in Ordnung, auch wenn Sie einige der Enum-Werte aus, um schreiben passieren.

Weitere Informationen zu dieser Technik finden Sie hier und hier .

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

Ich denke, das ist besser als

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

Incase die Größe der Array-Änderungen.

Sie können die gesamte statische Initialisierer Sache tun, wie oben beschrieben, aber es kann eine echte Bummer, wenn Ihre Array-Größe ändert sein (wenn Ihr Array embiggens, wenn Sie Sie Müll nicht über die entsprechenden zusätzlichen initializers hinzufügen bekommen).

memset gibt Ihnen eine Laufzeit-Hit für die Arbeit zu tun, aber kein Code-Größe Hit richtig gemacht ist immun gegen Array-Größe ändert. Ich würde in fast allen Fällen mit dieser Lösung, wenn das Array größer war als, sagen wir, ein paar Dutzend Elemente.

Wenn es wirklich wichtig war, dass das Array statisch erklärt wurde, würde ich ein Programm schreiben, das Programm für mich zu schreiben, und es ist Teil des Build-Prozesses machen.

Hier ist eine andere Art und Weise:

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

Siehe auch:

C-Erweiterungen

Designated inits

Dann die Frage: Wann kann man den Einsatz C-Erweiterungen

Das Codebeispiel ist oben in einem eingebetteten System und wird nie das Licht von einem anderen Compiler sehen.

Für ‚normale‘ Datentypen initialisiert (wie int Arrays), können Sie die Klammer-Notation verwenden, aber es wird die Werte nach dem letzten Null, wenn es noch Platz im Array ist:

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

Eine etwas tongue-in-cheek Antwort; schreiben die Anweisung

array = initial_value

in Ihrer Lieblings-Array-fähigen Sprache (ich ist Fortran, aber es gibt viele andere), und verknüpft es mit Ihrem C-Code. Sie würden wahrscheinlich wickeln wollen bis eine externe Funktion sein.

Wenn das Array geschieht mit der Größe von int oder Ihrem mem-Muster der Größe int oder irgendetwas zu sein, paßt genau mal in einen int (dh alle Nullen oder 0xA5A5A5A5), der beste Weg, zu verwenden ist memset () .

Ansonsten nennt Memcpy () in einer Schleife um den Index zu bewegen.

Es ist eine schnelle Methode zum initialisieren array eines beliebigen Typs mit dem angegebenen Wert.Es funktioniert sehr gut mit großen arrays.Der Algorithmus ist wie folgt:

  • initialisieren erste element des Arrays (üblicher Weise)
  • Kopie Teil, die festgelegt wurde, in den Teil, der nicht gesetzt wurde, wird die Verdoppelung der Größe mit jedem weiteren Kopiervorgang

Für 1 000 000 Elemente int array es ist 4 mal schneller als normale loop-Initialisierung (i5, 2 Kerne, 2,3 GHz, 4GiB Speicher, 64 bits):

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

Niemand hat den Index angegebenen Reihenfolge die Elemente des initialisierten Array zuzugreifen. Mein Beispielcode wird ein anschauliches Beispiel geben.

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

Die Ausgabe lautet:

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

Schneiden durch alle Chatter, die kurze Antwort ist, dass, wenn Sie bei der Optimierung bei der Kompilierung wenden Sie werden nicht besser als dies tun:

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

Zusätzlicher Bonus: Der Code ist eigentlich lesbar:)

  1. Wenn Ihr Array als statisch deklariert wird oder global, alle Elemente im Array bereits Standard Standardwert 0 hat.
  2. Einige Compiler gesetzt Array ist die Standardeinstellung auf 0 im Debug-Modus.
  3. Es ist einfach standardmäßig auf 0 zu setzen: int array [10] = {0};
  4. jedoch für andere Werte, die Sie verwenden memset () oder Schleife;

Beispiel:     int array [10];     Memset (array, -1, 10 * sizeof (int));

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

Es wird die o / p 5 5 5 5 5 5 ...... bis der Größe der gesamten Anordnung geben

Ich weiß, dass Benutzer Tarski diese Frage in ähnlicher Weise beantwortet, aber ich noch ein paar weiteren Details. Vergib einige meiner C für mich ein wenig eingerostet schon mal dabei bin, da ich eher geneigt bin zu wollen, C ++ verwenden, aber hier geht es.


Wenn Sie wissen, die Größe des Arrays vor der Zeit ...

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

Es gibt ein paar Einschränkungen oben; ist, dass UINT myArray[size]; nicht direkt bei der Deklaration initialisiert wird, aber schon am nächsten Codeblock oder Funktionsaufruf tut jedes Element des Arrays auf den gleichen Wert, den Sie wollen initialisieren. Der andere Nachteil ist, würden Sie einen initializing function schreiben für jede type werden Sie unterstützen, und Sie würden auch die printArray() Funktion ändern müssen, um diese Arten zu unterstützen.


Sie können versuchen, diesen Code mit einem Online-complier gefunden hier .

Für die verzögerte Initialisierung (das heißt Klassenmember Konstruktorinitialisierung) betrachten:

int a[4];

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

Zurück in dem Tag (und ich sage nicht, es ist eine gute Idee), wir das erste Element gesetzt haben, und dann:

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

Nicht einmal sicher, es würde mehr arbeiten (das über die Umsetzung der Memcpy abhängen würde), aber es funktioniert, indem wiederholt das Ausgangselement zum nächsten Kopieren -. Funktioniert auch für Arrays von Strukturen

Ich sehe keine Anforderungen in der Frage, so muss die Lösung generisch sein: Initialisierung eines nicht spezifizierten möglicherweise mehrdimensionales Array aus nicht näher bezeichnet möglicherweise Strukturelemente mit einem Anfangselement Wert gebaut:

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

Ergebnis:

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: start+element_size zu (char*)start+element_size geändert

Ich weiß, dass die ursprüngliche Frage ausdrücklich erwähnt C und C ++ nicht, aber wenn man (wie ich) hier kommt Suche nach einer Lösung für C ++ Arrays, hier ist ein netter Trick:

Wenn Ihr Compiler unterstützt falten Ausdrücke , können Sie Vorlage Magie und std::index_sequence eine Initialisiererliste mit dem Wert zu generieren, die Sie wollen. Und Sie können es auch constexpr und fühle mich wie ein Chef:

#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

Sie können an dem Code bei der Arbeit (bei Wandbox)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top