Как инициализировать все элементы массива одним и тем же значением?

c arrays initialization

1676771 просмотра

21 ответа

26147 Репутация автора

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

Автор: Matt Источник Размещён: 14.10.2008 01:13

Ответы (21)


1106 плюса

33711 Репутация автора

Решение

Если это значение не равно 0 (в этом случае вы можете опустить некоторую часть инициализатора, а соответствующие элементы будут инициализированы равными 0), простого способа нет.

Не забывайте об очевидном решении, хотя:

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

Элементы с пропущенными значениями будут инициализированы в 0:

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

Так что это инициализирует все элементы в 0:

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

В C ++ пустой список инициализации также инициализирует каждый элемент в 0. Это не разрешено с C:

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

Помните, что объекты со статической продолжительностью хранения будут инициализироваться до 0, если не указан инициализатор:

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

И то, что «0» не обязательно означает «все биты-ноль», поэтому использование вышеупомянутого лучше и более переносимо, чем memset (). (Значения с плавающей точкой будут инициализированы в +0, указатели на нулевое значение и т. Д.)

Автор: aib Размещён: 14.10.2008 01:17

5 плюса

18394 Репутация автора

Для инициализации «обычных» типов данных (например, массивов int) вы можете использовать скобочную запись, но она обнулит значения после последней, если в массиве еще есть место:

// put values 1-8, then two zeroes
int list[10] = {1,2,3,4,5,6,7,8};
Автор: warren Размещён: 14.10.2008 01:17

11 плюса

41023 Репутация автора

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

memset дает вам попадание во время выполнения для выполнения работы, но ни одно правильное совпадение по размеру кода не застраховано от изменений размера массива. Я бы использовал это решение почти во всех случаях, когда массив был больше, скажем, нескольких десятков элементов.

Если бы было действительно важно, чтобы массив был статически объявлен, я бы написал программу, которая напишет программу для меня и сделает ее частью процесса сборки.

Автор: plinth Размещён: 14.10.2008 01:29

22 плюса

3603 Репутация автора

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

Я думаю это лучше чем

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

Incase размер массива изменений.

Автор: Tarski Размещён: 14.10.2008 01:34

4 плюса

2677 Репутация автора

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

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

Автор: ddimitrov Размещён: 14.10.2008 01:59

61 плюса

3909 Репутация автора

Если вы хотите, чтобы каждый член массива был явно инициализирован, просто пропустите измерение из объявления:

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

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

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

хорошо, но

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

не является.

Автор: Frank Szczerba Размещён: 14.10.2008 06:30

8 плюса

453 Репутация автора

Вот еще один способ:

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

Увидеть:

C-расширения

Назначенные единицы

Затем задайте вопрос: когда можно использовать расширения C?

Пример кода выше находится во встроенной системе и никогда не увидит свет от другого компилятора.

Автор: humble_guru Размещён: 14.10.2008 10:12

361 плюса

27517 Репутация автора

Если ваш компилятор GCC, вы можете использовать следующий синтаксис:

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

Ознакомьтесь с подробным описанием: http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Designated-Inits.html

Автор: qrdl Размещён: 16.10.2008 07:38

-1 плюса

2118 Репутация автора

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

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

Результат:

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'

РЕДАКТИРОВАТЬ: start+element_sizeизменено на(char*)start+element_size

Автор: sambowry Размещён: 13.10.2009 11:40

168 плюса

56651 Репутация автора

Для статической инициализации большого массива с одним и тем же значением без множественного копирования-вставки вы можете использовать макросы:

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

Если вам нужно изменить значение, вы должны сделать замену только в одном месте.

Редактировать: возможные полезные расширения

(любезно предоставлено Джонатаном Леффлером )

Вы можете легко обобщить это с помощью:

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

Вариант может быть создан с использованием:

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

это работает со структурами или составными массивами.

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

имена макросов являются предметом переговоров.

Автор: mouviciel Размещён: 14.10.2009 10:27

6 плюса

68926 Репутация автора

Слегка насмешливый ответ; написать заявление

array = initial_value

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

Автор: High Performance Mark Размещён: 14.10.2009 10:33

46 плюса

46998 Репутация автора

Я видел некоторый код, который использовал этот синтаксис:

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

Особенно полезно это сделать, если вы создаете массив, использующий перечисления в качестве индекса:

enum
{
    ERR_OK,
    ERR_FAIL,
    ERR_MEMORY
};

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

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

Это поддерживает порядок, даже если вы пишете некоторые из перечисляемых значений не по порядку.

Подробнее об этой технике можно узнать здесь и здесь .

Автор: abelenky Размещён: 21.03.2012 09:02

3 плюса

6721 Репутация автора

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

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

Для массива 1 000 000элементов intэто в 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;
}
Автор: Maciej Размещён: 29.07.2015 12:17

1 плюс

161 Репутация автора

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

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

Автор: Hannah Zhang Размещён: 29.07.2015 01:21

2 плюса

5199 Репутация автора

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

#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
Автор: hkBattousai Размещён: 06.02.2016 03:24

1 плюс

141 Репутация автора

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

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

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

Автор: JWDN Размещён: 05.11.2016 04:12

0 плюса

167 Репутация автора

#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 ...... до размера всего массива

Автор: Dadhich Sourav Размещён: 26.10.2017 08:31

0 плюса

4659 Репутация автора

Я знаю, что пользователь 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()функцию для поддержки этих типов.


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

Автор: Francis Cugler Размещён: 28.01.2018 07:30

0 плюса

1604 Репутация автора

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

int a[4];

unsigned int size = sizeof(a) / sizeof(a[0]);
for (unsigned int i = 0; i < size; i++)
  a[i] = 0;
Автор: nikc Размещён: 19.10.2018 05:08

0 плюса

2098 Репутация автора

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

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

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

Автор: Mike Размещён: 14.01.2019 08:53

0 плюса

398 Репутация автора

Я знаю, что в первоначальном вопросе явно упоминается 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)

Автор: Clemens Sielaff Размещён: 13.02.2019 09:44
Вопросы из категории :
32x32