У меня есть большой массив в C (а не С++, если это имеет значение). Я хочу инициализировать все члены с одинаковым значением. Я мог бы поклясться, что когда-то знал простой способ сделать это. Я мог бы использовать memset()
в моем случае, но не существует способа сделать это, который встроен прямо в синтаксис C?
Если это значение равно 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, указывает на нулевое значение и т.д.)
Если ваш компилятор GCC, вы можете использовать следующий синтаксис:
int array[1024] = {[0 ... 1023] = 5};
Посмотрите подробное описание: http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Designated-Inits.html
memset()
Для статической инициализации большого массива с тем же значением, без множественной копии-вставки, вы можете использовать макросы:
#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) };
имена макросов являются оборотными.
Если вы хотите, чтобы каждый член массива был явно инициализирован, просто опустите измерение из объявления:
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} };
нет.
int myPoints[10][] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9} };
Я видел код, который использовал этот синтаксис:
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)
};
Это ведет к упорядочению, даже если вам не удалось написать некоторые из значений перечисления не в порядке.
char const *array[] = { ... };
или даже char const * const array[] = { ... };
не так ли?
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...
измените размер массива.
memset(myArray, VALUE, ARRAY_SIZE);
, это в основном просто более медленная и более подробная версия memset(myArray, VALUE, ARRAY_SIZE);
Вы можете сделать всю статическую инициализаторную вещь, как описано выше, но это может быть реальным обломком, когда изменяется размер вашего массива (когда ваш массив активируется, если вы не добавляете соответствующие дополнительные инициализаторы, вы получаете мусор).
memset дает вам время выполнения для выполнения работы, но ни один размер кода, сделанный правильно, не защищен от изменений размера массива. Я бы использовал это решение почти во всех случаях, когда массив был больше, чем, скажем, несколько десятков элементов.
Если было действительно важно, что массив был объявлен статически, я бы написал программу для написания программы для меня и сделаю ее частью процесса сборки.
Вот еще один способ:
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},
};
См:
Назначенные inits
Затем задайте вопрос: когда можно использовать расширения C?
Образец кода выше во встроенной системе и никогда не увидит свет от другого компилятора.
Немного вялый ответ; напишите выражение
array = initial_value
на вашем любимом языке с поддержкой массива (мой - Fortran, но есть много других) и привяжите его к вашему C-коду. Вероятно, вы захотите его обернуть, чтобы быть внешней функцией.
Для инициализации "нормальных" типов данных (например, массивов int) вы можете использовать нотацию в виде скобок, но она будет равна нулю после последнего, если в массиве все еще есть:
// put values 1-8, then two zeroes
int list[10] = {1,2,3,4,5,6,7,8};
Если массив имеет значение int или что-либо с размером int или вашим размером mem-шаблона, то подходит для точных времен в int (т.е. все нули или 0xA5A5A5A5), лучший способ - использовать memset().
В противном случае вызовите memcpy() в цикле, перемещающем индекс.
Существует быстрый способ инициализации массива любого типа с заданным значением. Он отлично работает с большими массивами. Алгоритм выглядит следующим образом:
Для массива 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;
}
memfill()
около 1200 мкс. Однако на последующих итерациях цикл занимает около 900-1000 мкс, а код memfill()
1000-1300 мкс. На первую итерацию, вероятно, влияет время заполнения кеша. memfill()
тесты и memfill()
будет медленным в первый раз.
Никто не упомянул индексный порядок доступа к элементам инициализированного массива. Мой примерный код даст иллюстративный пример.
#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
<iostream>
не является допустимым C
как std::cout
, std::cin
и т. д. является частью std::namespace
а C
не поддерживает namespaces
. Попробуйте вместо этого использовать <stdio.h>
для printf(...)
.
Вы можете использовать функцию memset.
void *memset(void *array, int value, unsigned sizeofarray);
Пересекая всю болтовню, короткий ответ заключается в том, что если вы включите оптимизацию во время компиляции, вы не будете лучше этого делать:
int i,value=5,array[1000];
for(i=0;i<1000;i++) array[i]=value;
Добавлен бонус: код действительно разборчивый:)
Пример: int array [10]; memset (массив, -1, 10 * sizeof (int));
Я знаю, что пользователь 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()
для поддержки этих типов.
Вы можете попробовать этот код с помощью онлайн-компилятора, найденного здесь.
#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...... до размера целого массива
Я не вижу никаких требований в вопросе, поэтому решение должно быть общим: инициализация неопределенного, возможно многомерного массива, построенного из неуказанных возможных структурных элементов с начальным значением элемента:
#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
sizeof(void)
действительным.
enum { HYDROGEN = 1, HELIUM = 2, CARBON = 6, NEON = 10, … };
иstruct element { char name[15]; char symbol[3]; } elements[] = { [NEON] = { "Neon", "Ne" }, [HELIUM] = { "Helium", "He" }, [HYDROGEN] = { "Hydrogen", "H" }, [CARBON] = { "Carbon", "C" }, … };
, Если вы удалите многоточие…
, эти фрагменты будут скомпилированы в C99 или C11.