How to initialize all members of an array to the same value?

随声附和 提交于 2019-11-25 21:39:41

问题


I have a large array in C (not C++ if that makes a difference). I want to initialize all members to the same value. I could swear I once knew a simple way to do this. I could use memset() in my case, but isn\'t there a way to do this that is built right into the C syntax?


回答1:


Unless that value is 0 (in which case you can omit some part of the initializer and the corresponding elements will be initialized to 0), there's no easy way.

Don't overlook the obvious solution, though:

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

Elements with missing values will be initialized to 0:

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

So this will initialize all elements to 0:

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

In C++, an empty initialization list will also initialize every element to 0. This is not allowed with C:

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

Remember that objects with static storage duration will initialize to 0 if no initializer is specified:

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

And that "0" doesn't necessarily mean "all-bits-zero", so using the above is better and more portable than memset(). (Floating point values will be initialized to +0, pointers to null value, etc.)




回答2:


If your compiler is GCC you can use following syntax:

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

Check out detailed description: http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Designated-Inits.html




回答3:


For statically initializing a large array with the same value, without multiple copy-paste, you can use macros:

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

If you need to change the value, you have to do the replacement at only one place.

Edit: possible useful extensions

(courtesy of Jonathan Leffler)

You can easily generalize this with:

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

A variant can be created using:

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

that works with structures or compound 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) };

macro names are negotiable.




回答4:


If you want to ensure that every member of the array is explicitly initialized, just omit the dimension from the declaration:

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

The compiler will deduce the dimension from the initializer list. Unfortunately, for multidimensional arrays only the outermost dimension may be omitted:

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

is OK, but

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

is not.




回答5:


I saw some code that used this syntax:

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

Where it becomes particularly useful is if you're making an array that uses enums as the index:

enum
{
    ERR_OK,
    ERR_FAIL,
    ERR_MEMORY
};

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

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

This keeps things in order, even if you happen to write some of the enum-values out of order.

More about this technique can be found here and here.




回答6:


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

I think this is better than

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

incase the size of the array changes.




回答7:


You can do the whole static initializer thing as detailed above, but it can be a real bummer when your array size changes (when your array embiggens, if you don't add the appropriate extra initializers you get garbage).

memset gives you a runtime hit for doing the work, but no code size hit done right is immune to array size changes. I would use this solution in nearly all cases when the array was larger than, say, a few dozen elements.

If it was really important that the array was statically declared, I'd write a program to write the program for me and make it part of the build process.




回答8:


Here is another way:

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

See:

C-Extensions

Designated inits

Then ask the question: When can one use C extensions?

The code sample above is in an embedded system and will never see the light from another compiler.




回答9:


For initializing 'normal' data types (like int arrays), you can use the bracket notation, but it will zero the values after the last if there is still space in the array:

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



回答10:


A slightly tongue-in-cheek answer; write the statement

array = initial_value

in your favourite array-capable language (mine is Fortran, but there are many others), and link it to your C code. You'd probably want to wrap it up to be an external function.




回答11:


If the array happens to be int or anything with the size of int or your mem-pattern's size fits exact times into an int (i.e. all zeroes or 0xA5A5A5A5), the best way is to use memset().

Otherwise call memcpy() in a loop moving the index.




回答12:


There is a fast way to initialize array of any type with given value. It works very well with large arrays. Algorithm is as follows:

  • initialize first element of the array (usual way)
  • copy part which has been set into part which has not been set, doubling the size with each next copy operation

For 1 000 000 elements int array it is 4 times faster than regular loop initialization (i5, 2 cores, 2.3 GHz, 4GiB memory, 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;
}



回答13:


Nobody has mentioned the index order to access the elements of the initialized array. My example code will give an illustrative example to it.

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

The output is:

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



回答14:


Cutting through all the chatter, the short answer is that if you turn on optimization at compile time you won't do better than this:

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

Added bonus: the code is actually legible :)




回答15:


  1. If your array is declared as static or is global, all the elements in the array already have default default value 0.
  2. Some compilers set array's the default to 0 in debug mode.
  3. It is easy to set default to 0 : int array[10] = {0};
  4. However, for other values, you have use memset() or loop;

example: int array[10]; memset(array,-1, 10 *sizeof(int));




回答16:


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

It will give the o/p 5 5 5 5 5 5 ...... till the size of whole array




回答17:


I know that user Tarski answered this question in a similar manner, but I added a few more details. Forgive some of my C for I'm a bit rusty at it since I'm more inclined to want to use C++, but here it goes.


If you know the size of the array ahead of time...

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

There are a few caveats above; one is that UINT myArray[size]; is not directly initialized upon declaration, however the very next code block or function call does initialize each element of the array to the same value you want. The other caveat is, you would have to write an initializing function for each type you will support and you would also have to modify the printArray() function to support those types.


You can try this code with an online complier found here.




回答18:


For delayed initialization (i.e. class member constructor initialization) consider:

int a[4];

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



回答19:


Back in the day (and I'm not saying it's a good idea), we'd set the first element and then:

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

Not even sure it would work any more (that would depend on the implementation of memcpy) but it works by repeatedly copying the initial element to the next - even works for arrays of structures.




回答20:


If you mean in parallel, I think the comma operator when used in conjunction with an expression can do that:

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

or if you mean in a single construct, you could do that in a for loop:

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

//Note the comma operator in an arguments list is not the parallel operator described above;

You can initialize an array decleration:

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

You can make a call to malloc/calloc/sbrk/alloca/etc to allocate a fixed region of storage to an object:

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

and access the members by:

*(array + index)

Etc.




回答21:


I see no requirements in the question, so the solution must be generic: initialization of an unspecified possibly multidimensional array built from unspecified possibly structure elements with an initial member value:

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

Result:

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 changed to (char*)start+element_size




回答22:


I know the original question explicitly mentions C and not C++, but if you (like me) came here looking for a solution for C++ arrays, here's a neat trick:

If your compiler supports fold expressions, you can use template magic and std::index_sequence to generate an initializer list with the value that you want. And you can even constexpr it and feel like a boss:

#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

You can take a look at the code at work (at Wandbox)



来源:https://stackoverflow.com/questions/201101/how-to-initialize-all-members-of-an-array-to-the-same-value

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!