Wie Sie initialisiert alle Mitglieder eines Arrays auf den gleichen Wert?
-
03-07-2019 - |
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?
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:
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:)
- Wenn Ihr Array als statisch deklariert wird oder global, alle Elemente im Array bereits Standard Standardwert 0 hat.
- Einige Compiler gesetzt Array ist die Standardeinstellung auf 0 im Debug-Modus.
- Es ist einfach standardmäßig auf 0 zu setzen: int array [10] = {0};
- 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)