У меня есть большой массив в C (не C++, если это имеет значение). Я хочу инициализировать все члены с одинаковым значением.
Могу поклясться, что когда-то знал простой способ сделать это. Я мог бы использовать memset() в моем случае, но разве нет способа сделать это, встроенного прямо в синтаксис C?
На самом деле ответ abelenky использует назначенный инициализатор, но не полностью сформирован код инициализации
memset () может помочь, но зависит от значения.
Конкретное обсуждение memset(): stackoverflow.com/questions/7202411/… Я думаю, что это работает только для 0.





Если это значение не равно 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, указатели на нулевое значение и т. д.)
Читая стандарт C++, вы также можете сделать int array [10] = {}; в нулевую инициализацию. У меня нет стандарта C, чтобы проверить, что это действительно C.
Глядя на раздел 6.7.8 «Инициализация стандарта C99», не видно, что разрешен пустой список инициализаторов.
C99 имеет много хороших функций для инициализации структур и массивов; единственная функция, которой он не обладает (но был у Fortran IV, 1966), - это способ повторения определенного инициализатора для массива.
А как насчет float * = new float [10]; это тоже будет инициализировано нулем?
Это вызовет конструктор по умолчанию, который, как только вы пройдете аргумент о том, существует ли на самом деле является конструктор для примитивных типов, также должен выполнить нулевую инициализацию.
Хотя, конечно, вы должны спросить, выполняет ли std::vector<int>(10) нулевую инициализацию.
@aib можем ли мы использовать ту же технику для инициализации двумерного массива, размещенного в куче, с помощью malloc (sizeof (int [ROW] [COL])). Спасибо
int myArray[10] = { -1 }; просто не работает, см. codepad.org/ckuy54OZ !!
@CetinSert: Что значит не работает? Он делает именно то, что должен делать этот ответ. Он не делает то, что говорит комментарий в вашем коде, но этот комментарий неверен.
@BenjaminLindley Вы видите комментарий в int myArray[10] = { 0 }; //all elements 0 из ответа? Что ж, когда я вместо этого использую -1, это элемент только первый, для которого установлено значение -1 и не все, как заявлено. В ссылке на кодовую панель есть фрагмент кода, подтверждающий, что неверно предполагать, что назначение = { x }; действительно устанавливает элементы все в x. Я хочу, чтобы это видели другие.
@CetinSert: Вы единственный, кто заявил в этом комментарии, что для всех элементов будет установлено значение -1. В этом ответе справедливо утверждается, что все неуказанные элементы обнуляются. Результаты вашего кода соответствуют этому утверждению.
О, очевидно, я разбирал ответ снизу, прокручивая страницу вверх, и рассматривал назначение = { x }; в отрыве от контекста предыдущего текста o_O, из-за чего я потерялся. Прошу прощения за загромождение раздела комментариев ^ _ ^ ". С этого дня я постараюсь полностью учитывать контекст при чтении ответов SO, чтобы не стыдить себя снова.
Не думаю, что я это еще видел: int myArray[] = {[3] = 123, [7] = 23}; дает вам {0, 0, 0, 123, 0, 0, 0, 23}
@akofink: Посмотрите ответ qrdl чуть ниже. Это расширение GCC.
Может ли кто-нибудь доказать это утверждение с помощью стандарта C? Он уже включен в C90? «Если это значение не равно 0 (в этом случае вы можете опустить некоторую часть инициализатора, и соответствующие элементы будут инициализированы до 0)»
В других новостях, по-видимому, вы не можете использовать переменную в качестве размера, если хотите инициализировать ее в той же строке.
int myArray [10] = {0}; // все элементы 0 неверно для C++. int myArray [10] = {5}; Он будет назначен только первому элементу.
@neo Это неверно, и ответ правильный. См. cplusplus.com/doc/tutorial/arrays - «Если объявлено с меньшим значением, для остальных элементов устанавливаются значения по умолчанию (что для основных типов означает, что они заполнены нулями)»
@MaxBarraclough: я думаю, что {0} в выражении инициализации даст значение по умолчанию для каждого типа объекта, кроме, возможно, объединений - false для логических значений, целочисленный ноль для всех целочисленных типов, ноль с плавающей запятой для всех типов с плавающей запятой, null для всех типы указателей и структуры, значения которых установлены в значения по умолчанию для соответствующих типов.
Я прочитал стандарты C99 и C11 и не могу найти никаких ссылок на инициализацию массива одним значением в фигурных скобках, как упомянуто выше. int arraything [6] = {8}; Может ли кто-нибудь указать, откуда это?
@Fratink См. §6.7.8.21: «Если в списке, заключенном в фигурные скобки, меньше инициализаторов, чем элементов или членов агрегата, или меньше символов в строковом литерале, используемом для инициализации массива известного размера, чем элементов в массива, остальная часть агрегата должна быть инициализирована неявно так же, как объекты, которые имеют статическую продолжительность хранения ".
Для инициализации «нормальных» типов данных (например, массивов int) вы можете использовать обозначение скобок, но оно обнулит значения после последнего, если в массиве еще есть место:
// put values 1-8, then two zeroes
int list[10] = {1,2,3,4,5,6,7,8};
Вы можете сделать все, что касается статического инициализатора, как описано выше, но это может стать настоящим обломом, когда размер вашего массива изменяется (когда ваш массив эмбиггируется, если вы не добавляете соответствующие дополнительные инициализаторы, вы получаете мусор).
memset дает вам возможность выполнить эту работу во время выполнения, но ни один правильный размер кода не застрахован от изменений размера массива. Я бы использовал это решение почти во всех случаях, когда массив был больше, скажем, нескольких десятков элементов.
Если бы было действительно важно, чтобы массив был объявлен статически, я бы написал программу для написания программы за меня и сделал ее частью процесса сборки.
Не могли бы вы добавить пример использования memset для инициализации массива?
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 для инициализации массива int некоторым значением больше 255? memset работает только в том случае, если размер массива байтовый.
@Benson: Вы не можете заменить приведенный выше код на memset на платформах, где sizeof (int)> sizeof (char). Попробуй это.
Если массив представляет собой int или что-либо с размером int или размер вашего mem-шаблона соответствует точному времени в int (т.е. все нули или 0xA5A5A5A5), лучший способ - использовать memset ().
В противном случае вызовите memcpy () в цикле, перемещая индекс.
Если вы хотите убедиться, что каждый член массива инициализирован явно, просто опустите измерение в объявлении:
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} };
Нет. Вы опускаете самое сокровенное измерение, что недопустимо. Это приведет к ошибке компилятора.
И инициализаторы, и вывод длины были введены в C99.
@Palec: Нет - вывод длины был в C со времен предстандартного C (с тех пор, как было опубликовано K&R 1st Edition, и, вероятно, некоторое время до этого). Назначенные инициализаторы были новыми в C99, но в нем не используются назначенные инициализаторы.
Вот еще один способ:
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?
Приведенный выше пример кода находится во встроенной системе и никогда не увидит свет от другого компилятора.
Если ваш компилятор - GCC, вы можете использовать следующий синтаксис:
int array[1024] = {[0 ... 1023] = 5};
Ознакомьтесь с подробным описанием: http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Designated-Inits.html
@qrdl Я попытался инициализировать 2D-массив, динамически размещаемый в куче, с помощью malloc (sizeof (int [row] [col])) и получил ошибку времени компиляции в строке, где используется эта строка: arr [row] [col] = {[0 ... строка -1] [0 ... col-1] = -1}; Ошибка, которую я получил, была «ожидаемое выражение перед токеном '{'». Есть идеи по этому поводу? Спасибо
@abhi То, что вы пытаетесь сделать, - это не инициализация, а назначение, этот синтаксис нельзя использовать в такой ситуации, вам будет лучше использовать memset()
@qrdl спасибо за ответ .. так что в основном для динамического распределения я не могу использовать эту технику. правильный?
И этот синтаксис приводит к огромному увеличению размера файла скомпилированных двоичных файлов. Для N = 65536 (вместо 1024) размер моего двоичного файла увеличивается с 15 КБ до 270 КБ !!
Компилятор @CetinSert должен добавить 65536 int в статические данные, что составляет 256 КБ - именно такое увеличение размера, которое вы наблюдали.
@qrdl, почему вы не упомянули об этом в своем ответе?
@CetinSert Почему я должен? Это стандартное поведение компилятора, не предназначенное для определенных инициализаторов. Если вы статически инициализируете 65536 int, например int foo1 = 1, foo2 = 1, ..., foo65536 =1;, вы получите такое же увеличение размера.
еще лучше: "int array [] = {[0 ... 1023] = 5}", размер массива будет автоматически установлен на 1024, его проще и безопаснее изменять.
@Francois или bool array[][COLS] = { [0...ROWS-1][0...COLS-1] = true} для двумерного массива, хотя я не уверен, что это более читабельно, чем полная форма.
Я подумал, что когда вы говорите gcc, это также относится и к g++.
Зачем нужно добавлять, 65536 int? Разве вы не указываете его размер 1024?
@AkshayImmanuelD Пожалуйста, прочтите обсуждение с Цетином Сертом с самого начала.
Есть ли способ сделать что-то подобное для структур? Если да, ответьте здесь: stackoverflow.com/questions/61240589/….
@qrdl Может ли g ++ использовать этот метод?
Я не вижу требований в вопросе, поэтому решение должно быть общим: инициализация неуказанного, возможно, многомерного массива, построенного из неуказанных, возможно, структурных элементов с начальным значением члена:
#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
Я сомневаюсь, что это решение. Я не уверен, действительно ли sizeof(void) действителен.
Не работает. Инициализируются только первые два, остальные не инициализируются. Я использую GCC 4.0 в Mac OS X 10.4.
Это вызывает неопределенное поведение, поскольку исходные данные во втором memcpy() перекрываются с целевым пространством. С наивной реализацией memcpy() он может работать, но не требуется, чтобы система заставляла его работать.
Для статической инициализации большого массива с тем же значением без многократного копирования и вставки можно использовать макросы:
#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) };
имена макросов обсуждаются.
Я бы рассмотрел это только в крайних случаях, конечно, memset - более элегантный способ выразить это.
Конечно, memset () - это то, что вам нужно. Я понял, что OP искал альтернативу.
Если данные должны быть доступными для ПЗУ, memset использовать нельзя.
Препроцессор фактически сгенерирует код из #defines. Чем больше размер массива, тем больше размер исполняемого файла. Но однозначно + за идею;)
memset инициализируется символом. Его нельзя использовать для инициализации массива int до значения типа 42 .. Значение 0 можно использовать для инициализации до нуля. значение -1 можно использовать для инициализации массива в -1.
@AmigableClarkKant, что вы имели в виду под "ROM-совместимым"?
@Alcott, на старых компьютерах и все еще во многих встроенных системах код в конечном итоге помещается в EPROM или ПЗУ. ПЗУ-способный также стал обозначать во встроенных системах «код, помещенный во флэш-память», потому что он имеет примерно те же последствия, а именно, что память не может быть записана во время выполнения. Т.е. memset или любые другие инструкции по обновлению или изменению памяти использовать нельзя. Константы, тем не менее, могут быть выражены и записаны во флэш-память или записаны в ПЗУ перед запуском программы.
(Если флэш-память не используется как обычная файловая система, скажем, в Linux или Windows, и в этом случае флэш-память используется так же, как жесткий диск.) @Alcott.
@ u0b34a0f6ae: имейте в виду, что вы можете использовать этот метод также, если VAL_1X не одно целое число, а список. Подобно состояниям Amigable, это также путь для встроенных систем, где вы хотите определить значения инициализации EEPROM или флэш-памяти. В обоих случаях нельзя использовать memset().
@mouviciel - вопрос: включен ли индекс массива в ваш пример по какой-либо причине? то есть в моем компиляторе ANSI C int myArray[] = { VAL_32X, VAL_16X, VAL_4X, VAL_1X }; работает нормально. Я просто не уверен, есть ли тонкий недостаток в том, что не используется явное значение индекса. +1 за ваш ответ.
"VAL_64X ... где-то определен ... 42. Подождите? Что это должно делать?" Если мы когда-нибудь будем работать вместе, пожалуйста, просто используйте несколько дополнительных строк кода и сделайте их достаточно глупыми, чтобы кто-то вроде меня мог понять :)
Вы можете легко обобщить это с помощью #define VAL_1(X) X и #define VAL_2(X) VAL_1(X), VAL_1(X) и т. д. Вариант может быть создан с использованием #define STRUCTVAL_1(...) { __VA_ARGS__ }, #define STRUCTVAL_2(...) STRUCTVAL_1(__VA_ARGS__), STRUCTVAL_1(__VA_ARGS__) и т. д., Который работает со структурами или составными массивами. #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) }; - имена макросов обсуждаются.
@JonathanLeffler Это отличное расширение! Вы не возражаете, если я добавлю это к своему ответу?
Получите это! : D - Да, во что бы то ни стало пользуйтесь.
Слегка насмешливый ответ; напишите заявление
array = initial_value
на вашем любимом языке с поддержкой массивов (мой - Fortran, но есть много других) и свяжите его со своим кодом C. Вы, вероятно, захотите сделать его внешней функцией.
Я видел код, в котором использовался этот синтаксис:
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)
};
Это сохраняет порядок, даже если вы случайно записали некоторые из значений перечисления не по порядку.
Подробнее об этой технике можно найти в здесь и здесь.
Это синтаксис инициализатора C99, уже описанный в некоторых других ответах. Вы могли бы с пользой сделать декларацию в char const *array[] = { ... }; или даже char const * const array[] = { ... };, не так ли?
Есть быстрый способ инициализировать массив любого типа заданным значением. Он очень хорошо работает с большими массивами. Алгоритм следующий:
Для элементов 1 000 000 массив 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;
}
Извините, но это неправда. Возможно, вы забыли включить оптимизацию компиляции во время тестов (тестировали в режиме отладки?). Если я проверю это, цикл почти всегда на 50% быстрее, чем memfill («всегда» из-за некоторого колебания нагрузки на моей машине). И используя memset (a, 0, sizeof (a)); даже вдвое быстрее, чем loopfill.
Как и в случае с любым кодом для тестирования производительности, вам нужно быть предельно осторожным. Добавление цикла для выполнения кода синхронизации 10 раз (и удвоение размера массива до 20 МБ) показывает - для меня при работе на MacBook Pro с macOS Sierra 10.12.3 и с использованием GCC 6.3.0 - что в первый раз, используя цикл занимает около 4600 мкс, а код memfill() - около 1200 мкс. Однако на последующих итерациях цикл занимает около 900–1000 мкс, в то время как код memfill() занимает 1000–1300 мкс. На первую итерацию, вероятно, влияет время заполнения кеша. Поменяйте местами тесты, и memfill() будет медленным с первого раза.
пример: int array [10]; memset (массив, -1, 10 * sizeof (int));
Никто не упомянул порядок индекса для доступа к элементам инициализированного массива. В моем примере кода это будет наглядным примером.
#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(...).
Коротко говоря, если вы включите оптимизацию во время компиляции, вы не добьетесь большего успеха, чем это:
int i,value=5,array[1000];
for(i=0;i<1000;i++) array[i]=value;
Дополнительный бонус: код действительно читаемый :)
Вопрос конкретно по инициализации задан. Это явно не инициализация, а присвоение выполненной инициализации после. Это может быть сделано немедленно, но это еще не инициализация.
Совершенно бесполезен для большой статической таблицы поиска внутри функции, вызываемой много раз.
... не помните, что статические таблицы поиска внутри функций являются частью исходного вопроса - пусть это будет проще. Тем не менее, @Community, вероятно, справился с этим.
#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 ...... до размера всего массива
Я знаю, что пользователь 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() для поддержки этих типов.
Вы можете попробовать этот код с помощью онлайн-компилятора здесь.
Для отложенной инициализации (то есть инициализации конструктора члена класса) рассмотрите:
int a[4];
unsigned int size = sizeof(a) / sizeof(a[0]);
for (unsigned int i = 0; i < size; i++)
a[i] = 0;
Раньше (и я не говорю, что это хорошая идея) мы устанавливали первый элемент, а затем:
memcpy (&element [1], &element [0], sizeof (element)-sizeof (element [0]);
Даже не уверен, что он будет работать больше (это будет зависеть от реализации memcpy), но он работает, многократно копируя начальный элемент в следующий - даже работает для массивов структур.
Это не будет работать надежно. IMHO, Стандарт должен был предоставлять функции, похожие на memcpy, но указывать порядок копирования снизу вверх или сверху вниз в случае перекрытия, но это не так.
Как я уже сказал, это было то, что мы сделали, что не сработало бы надежно, но тогда мы были больше сосредоточены на эффективности, чем на избегании недокументированных функций. Хотя более эффективно копировать память вперед, в спецификации нет ничего, что говорило бы, что нельзя копировать ее назад, в случайном порядке или разбивать ее на несколько потоков. memmove () предоставляет возможность копирования без конфликтов.
Это эквивалентно коду в другом отвечать - и ошибочно. Использование memmove() не работает.
Я знаю, что в исходном вопросе явно упоминается 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)
Если вы имеете в виду параллельно, я думаю, что оператор запятой при использовании вместе с выражением может это сделать:
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)
И т.п.
Оператор запятой номинально гарантирует оценку слева направо. Если в выражениях нет побочных эффектов, тогда можно будет распараллелить операции, но это было бы необычно для компилятора.
Если размер массива известен заранее, можно использовать макрос препроцессора Boost C_ARRAY_INITIALIZE, чтобы выполнить грязную работу за вас:
#include <boost/preprocessor/repetition/enum.hpp>
#define C_ARRAY_ELEMENT(z, index, name) name[index]
#define C_ARRAY_EXPAND(name,size) BOOST_PP_ENUM(size,C_ARRAY_ELEMENT,name)
#define C_ARRAY_VALUE(z, index, value) value
#define C_ARRAY_INITIALIZE(value,size) BOOST_PP_ENUM(size,C_ARRAY_VALUE,value)
int array [1024] = {[0 ... 1023] = 5}; Поскольку приведенное выше работает нормально, но убедитесь, что между точками нет пробелов.
Используйте форматирование при размещении кода: stackoverflow.com/editing-help
Меня смутил int myArray[10] = { 0 }. Я думал, что это можно применить к любым другим константам. Но этого не произошло. Ваше решение помогает.
Ни в одном из ответов до сих пор не упоминается обозначенная нотация инициализатора, которая возможна с C99 и выше. Например:
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.