Как инициализировать все члены массива одним и тем же значением? - PullRequest
885 голосов
/ 14 октября 2008

У меня большой массив в C (не C ++, если это имеет значение). Я хочу инициализировать все элементы с одинаковым значением. Я могу поклясться, что когда-то знал простой способ сделать это. Я мог бы использовать memset() в моем случае, но нет ли способа сделать это встроенным прямо в синтаксис C?

Ответы [ 21 ]

4 голосов
/ 14 октября 2008

Если массив имеет тип int или что-либо с размером int или размер вашего mem-шаблона соответствует точному времени в int (то есть все нули или 0xA5A5A5A5), лучший способ - использовать memset () .

В противном случае вызовите memcpy () в цикле, перемещающем индекс.

3 голосов
/ 29 июля 2015

Существует быстрый способ инициализации массива любого типа с заданным значением. Это работает очень хорошо с большими массивами. Алгоритм выглядит следующим образом:

  • инициализировать первый элемент массива (обычным способом)
  • копировать часть, которая была установлена ​​в часть, которая не была установлена, удваивая размер с каждой следующей операцией копирования

Для 1 000 000 элементов * массив 1011 * это в 4 раза быстрее, чем обычная инициализация цикла (i5, 2 ядра, 2,3 ГГц, память 4 ГБ, 64 бита):

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;
}
1 голос
/ 05 ноября 2016

Разбивая всю болтовню, короткий ответ таков: если вы включите оптимизацию во время компиляции, вы не добьетесь большего успеха, чем эта:

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

Дополнительный бонус: код на самом деле разборчивый:)

1 голос
/ 06 февраля 2016

Никто не упомянул порядок индексов для доступа к элементам инициализированного массива. Мой пример кода даст наглядный пример.

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

Вывод:

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
1 голос
/ 29 июля 2015
  1. Если ваш массив объявлен как статический или глобальный, все элементы в массиве уже есть значение по умолчанию по умолчанию 0.
  2. Некоторые компиляторы устанавливают для массива значение по умолчанию 0 в режиме отладки.
  3. Легко установить значение по умолчанию 0: int array [10] = {0};
  4. Однако для других значений вы должны использовать memset () или loop;

пример: массив int [10]; memset (массив, -1, 10 * sizeof (int));

0 голосов
/ 13 февраля 2019

Я знаю, что в исходном вопросе явно упоминается C, а не C ++, но если вы (как и я) пришли сюда в поисках решения для массивов C ++, вот хитрый трюк:

Если ваш компилятор поддерживает сложение выражений , вы можете использовать шаблонную магию и std::index_sequence, чтобы сгенерировать список инициализатора с нужным вам значением. И вы даже можете constexpr это и почувствовать себя боссом:

#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

Вы можете взглянуть на код на работе (в Wandbox)

0 голосов
/ 14 января 2019

Раньше (и я не говорю, что это хорошая идея), мы установили первый элемент, а затем:

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

Даже не уверен, что он будет работать больше (это будет зависеть от реализации memcpy), но он работает путем многократного копирования исходного элемента в следующий - даже работает для массивов структур.

0 голосов
/ 19 октября 2018

Для отложенной инициализации (т.е. инициализации конструктора члена класса) учитывайте:

int a[4];

unsigned int size = sizeof(a) / sizeof(a[0]);
for (unsigned int i = 0; i < size; i++)
  a[i] = 0;
0 голосов
/ 28 января 2018

Я знаю, что пользователь Tarski ответил на этот вопрос аналогичным образом, но я добавил еще несколько деталей. Простите мне немного моего C, потому что я немного устала от этого, так как я более склонна хотеть использовать C ++, но здесь это идет.


Если вы заранее знаете размер массива ...

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

Есть несколько предостережений выше; одна из них заключается в том, что UINT myArray[size]; не инициализируется напрямую при объявлении, однако следующий блок кода или вызов функции инициализирует каждый элемент массива тем же значением, которое вы хотите. Другое предостережение: вам нужно написать initializing function для каждого type, который вы будете поддерживать, и вам также придется изменить функцию printArray() для поддержки этих типов.


Вы можете попробовать этот код с найденным онлайн компилятором здесь .

0 голосов
/ 26 октября 2017
#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 5 5 5 5 5 5 ...... до размера всего массива

...