Как инициализировать все элементы массива с одинаковым значением?
У меня есть большой массив в C (а не С++, если это имеет значение). Я хочу инициализировать все члены с одинаковым значением. Я мог бы поклясться, что когда-то знал простой способ сделать это. Я мог бы использовать memset()
в моем случае, но не существует способа сделать это, который встроен прямо в синтаксис C?
Ответы
Ответ 1
Если это значение равно 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
В С++ пустой список инициализации также инициализирует каждый элемент равным 0.
Это не разрешено с помощью C:
int myArray[10] = {}; // all elements 0 in C++
Помните, что объекты со статическим временем хранения инициализируются до 0, если нет
Инициализатор указан:
static int myArray[10]; // all elements 0
И что "0" не обязательно означает "all-bits-zero", поэтому использование вышеописанного
лучше и более переносимым, чем memset(). (Значения плавающей точки будут
инициализируется до +0, указывает на нулевое значение и т.д.)
Ответ 2
Если ваш компилятор GCC, вы можете использовать следующий синтаксис:
int array[1024] = {[0 ... 1023] = 5};
Посмотрите подробное описание:
http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Designated-Inits.html
Ответ 3
Для статической инициализации большого массива с тем же значением, без множественной копии-вставки, вы можете использовать макросы:
#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) };
имена макросов являются оборотными.
Ответ 4
Если вы хотите, чтобы каждый член массива был явно инициализирован, просто опустите измерение из объявления:
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} };
нет.
Ответ 5
Я видел код, который использовал этот синтаксис:
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)
};
Это ведет к упорядочению, даже если вам не удалось написать некоторые из значений перечисления не в порядке.
Подробнее об этой технике можно найти здесь и здесь.
Ответ 6
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...
измените размер массива.
Ответ 7
Вы можете сделать всю статическую инициализаторную вещь, как описано выше, но это может быть реальным обломком, когда изменяется размер вашего массива (когда ваш массив активируется, если вы не добавляете соответствующие дополнительные инициализаторы, вы получаете мусор).
memset дает вам время выполнения для выполнения работы, но ни один размер кода, сделанный правильно, не защищен от изменений размера массива. Я бы использовал это решение почти во всех случаях, когда массив был больше, чем, скажем, несколько десятков элементов.
Если было действительно важно, что массив был объявлен статически, я бы написал программу для написания программы для меня и сделаю ее частью процесса сборки.
Ответ 8
Вот еще один способ:
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-Extensions
Назначенные inits
Затем задайте вопрос: когда можно использовать расширения C?
Образец кода выше во встроенной системе и никогда не увидит свет от другого компилятора.
Ответ 9
Для инициализации "нормальных" типов данных (например, массивов int) вы можете использовать нотацию в виде скобок, но она будет равна нулю после последнего, если в массиве все еще есть:
// put values 1-8, then two zeroes
int list[10] = {1,2,3,4,5,6,7,8};
Ответ 10
Немного вялый ответ; напишите выражение
array = initial_value
на вашем любимом языке с поддержкой массива (мой - Fortran, но есть много других) и привяжите его к вашему C-коду. Вероятно, вы захотите его обернуть, чтобы быть внешней функцией.
Ответ 11
Если массив имеет тип int или что-либо с размером int или размер мем-шаблона соответствует точному времени в int (т.е. все нули или 0xA5A5A5A5), лучший способ - использовать memset().
В противном случае вызовите memcpy() в цикле, перемещающем индекс.
Ответ 12
Существует быстрый способ инициализации массива любого типа с заданным значением. Он отлично работает с большими массивами. Алгоритм выглядит следующим образом:
- инициализировать первый элемент массива (обычным способом)
- копия, которая была частично установлена, которая не была установлена, удваивая размер с каждой следующей операцией копирования.
Для массива 1 000 000
elements int
он в 4 раза быстрее, чем инициализация регулярного цикла (i5, 2 ядра, 2,3 ГГц, 4GiB-память, 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;
}
Ответ 13
Вы можете использовать функцию memset.
void *memset(void *array, int value, unsigned sizeofarray);
Ответ 14
Никто не упомянул индексный порядок доступа к элементам инициализированного массива. Мой примерный код даст иллюстративный пример.
#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
Ответ 15
Пересекая всю болтовню, короткий ответ заключается в том, что если вы включите оптимизацию во время компиляции, вы не будете лучше этого делать:
int i,value=5,array[1000];
for(i=0;i<1000;i++) array[i]=value;
Добавлен бонус: код действительно разборчивый:)
Ответ 16
- Если ваш массив объявлен как статический или глобальный, все элементы
в массиве уже есть значение по умолчанию 0.
- Некоторые компиляторы задают массив по умолчанию равным 0 в режиме отладки.
- По умолчанию установлено значение 0:
int array [10] = {0};
- Однако для других значений вы используете memset() или loop;
Пример: int array [10]; memset (массив, -1, 10 * sizeof (int));
Ответ 17
#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...... до размера целого массива
Ответ 18
Я знаю, что пользователь Tarski
ответил на этот вопрос аналогичным образом, но я добавил несколько подробностей. Простите некоторые из моих 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()
для поддержки этих типов.
Вы можете попробовать этот код с помощью онлайн-компилятора, найденного здесь.
Ответ 19
Для отложенной инициализации (т.е. инициализации конструктора члена класса) учтите:
int a[4];
unsigned int size = sizeof(a) / sizeof(a[0]);
for (unsigned int i = 0; i < size; i++)
a[i] = 0;
Ответ 20
В свое время (и я не говорю, что это хорошая идея), мы установили первый элемент, а затем:
memcpy (&element [1], &element [0], sizeof (element)-sizeof (element [0]);
Даже не уверен, что он будет работать больше (это будет зависеть от реализации memcpy), но он работает путем многократного копирования исходного элемента в следующий - даже работает для массивов структур.
Ответ 21
Если вы имеете в виду параллельно, я думаю, что оператор запятой при использовании в сочетании с выражением может сделать это:
a[1]=1, a[2]=2, ..., a[indexSize];
или если вы имеете в виду в одной конструкции, вы можете сделать это в цикле for:
for(int index = 0, value = 10; index < sizeof(array)/sizeof(array[0]); index++, value--)
array[index] = index;
//Обратите внимание, что оператор запятой в списке аргументов не является параллельным оператором, описанным выше;
Вы можете инициализировать замедление массива:
array[] = {1, 2, 3, 4, 5};
Вы можете вызвать malloc/calloc/sbrk/alloca/etc для выделения фиксированной области памяти для объекта:
int *array = malloc(sizeof(int)*numberOfListElements/Indexes);
и получить доступ к участникам с помощью:
*(array + index)
т.д.
Ответ 22
Я не вижу никаких требований в вопросе, поэтому решение должно быть общим: инициализация неопределенного, возможно многомерного массива, построенного из неуказанных возможных структурных элементов с начальным значением элемента:
#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'
EDIT: start+element_size
изменено на (char*)start+element_size
Ответ 23
Я знаю, что в первоначальном вопросе явно упоминается C, а не C++, но если вы (как и я) пришли сюда в поисках решения для массивов C++, то здесь есть хитрый трюк:
Если ваш компилятор поддерживает выражения сгиба, вы можете использовать шаблонную магию и std::index_sequence
, чтобы сгенерировать список инициализаторов с нужным вам значением. И вы даже можете constexpr
это почувствовать себя боссом:
#include <array>
/// [3]
/// This functions 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)