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

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

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

Ни в одном из ответов до сих пор не упоминается обозначенная нотация инициализатора, которая возможна с 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.

Jonathan Leffler 11.05.2014 18:40

На самом деле ответ abelenky использует назначенный инициализатор, но не полностью сформирован код инициализации

Rob11311 05.06.2014 18:17

memset () может помочь, но зависит от значения.

Nick 13.02.2015 15:23

Конкретное обсуждение memset(): stackoverflow.com/questions/7202411/… Я думаю, что это работает только для 0.

Ciro Santilli TRUMP BAN IS BAD 10.05.2016 21:55
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1 031
4
1 948 124
24
Перейти к ответу Данный вопрос помечен как решенный

Ответы 24

Ответ принят как подходящий

Если это значение не равно 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.

workmad3 14.10.2008 17:41

Глядя на раздел 6.7.8 «Инициализация стандарта C99», не видно, что разрешен пустой список инициализаторов.

Jonathan Leffler 14.10.2008 17:59

C99 имеет много хороших функций для инициализации структур и массивов; единственная функция, которой он не обладает (но был у Fortran IV, 1966), - это способ повторения определенного инициализатора для массива.

Jonathan Leffler 14.10.2008 18:00

А как насчет float * = new float [10]; это тоже будет инициализировано нулем?

Miek 30.08.2012 21:42

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

aib 30.08.2012 22:54

Хотя, конечно, вы должны спросить, выполняет ли std::vector<int>(10) нулевую инициализацию.

aib 30.08.2012 22:59

@aib можем ли мы использовать ту же технику для инициализации двумерного массива, размещенного в куче, с помощью malloc (sizeof (int [ROW] [COL])). Спасибо

abhi 15.03.2013 17:40

int myArray[10] = { -1 }; просто не работает, см. codepad.org/ckuy54OZ !!

Cetin Sert 28.03.2013 13:22

@CetinSert: Что значит не работает? Он делает именно то, что должен делать этот ответ. Он не делает то, что говорит комментарий в вашем коде, но этот комментарий неверен.

Benjamin Lindley 19.04.2013 07:58

@BenjaminLindley Вы видите комментарий в int myArray[10] = { 0 }; //all elements 0 из ответа? Что ж, когда я вместо этого использую -1, это элемент только первый, для которого установлено значение -1 и не все, как заявлено. В ссылке на кодовую панель есть фрагмент кода, подтверждающий, что неверно предполагать, что назначение = { x }; действительно устанавливает элементы все в x. Я хочу, чтобы это видели другие.

Cetin Sert 19.04.2013 08:56

@CetinSert: Вы единственный, кто заявил в этом комментарии, что для всех элементов будет установлено значение -1. В этом ответе справедливо утверждается, что все неуказанные элементы обнуляются. Результаты вашего кода соответствуют этому утверждению.

Benjamin Lindley 19.04.2013 09:02

О, очевидно, я разбирал ответ снизу, прокручивая страницу вверх, и рассматривал назначение = { x }; в отрыве от контекста предыдущего текста o_O, из-за чего я потерялся. Прошу прощения за загромождение раздела комментариев ^ _ ^ ". С этого дня я постараюсь полностью учитывать контекст при чтении ответов SO, чтобы не стыдить себя снова.

Cetin Sert 19.04.2013 09:05

Не думаю, что я это еще видел: int myArray[] = {[3] = 123, [7] = 23}; дает вам {0, 0, 0, 123, 0, 0, 0, 23}

akofink 24.04.2013 17:49

@akofink: Посмотрите ответ qrdl чуть ниже. Это расширение GCC.

aib 24.04.2013 21:16

Может ли кто-нибудь доказать это утверждение с помощью стандарта C? Он уже включен в C90? «Если это значение не равно 0 (в этом случае вы можете опустить некоторую часть инициализатора, и соответствующие элементы будут инициализированы до 0)»

Niklas Peter 21.11.2014 12:07

В других новостях, по-видимому, вы не можете использовать переменную в качестве размера, если хотите инициализировать ее в той же строке.

Jacqlyn 08.03.2015 05:44

int myArray [10] = {0}; // все элементы 0 неверно для C++. int myArray [10] = {5}; Он будет назначен только первому элементу.

neo 01.08.2018 12:27

@neo Это неверно, и ответ правильный. См. cplusplus.com/doc/tutorial/arrays - «Если объявлено с меньшим значением, для остальных элементов устанавливаются значения по умолчанию (что для основных типов означает, что они заполнены нулями)»

Max Barraclough 22.12.2019 16:07

@MaxBarraclough: я думаю, что {0} в выражении инициализации даст значение по умолчанию для каждого типа объекта, кроме, возможно, объединений - false для логических значений, целочисленный ноль для всех целочисленных типов, ноль с плавающей запятой для всех типов с плавающей запятой, null для всех типы указателей и структуры, значения которых установлены в значения по умолчанию для соответствующих типов.

supercat 30.01.2020 19:06

Я прочитал стандарты C99 и C11 и не могу найти никаких ссылок на инициализацию массива одним значением в фигурных скобках, как упомянуто выше. int arraything [6] = {8}; Может ли кто-нибудь указать, откуда это?

Fratink 06.05.2020 17:54

@Fratink См. §6.7.8.21: «Если в списке, заключенном в фигурные скобки, меньше инициализаторов, чем элементов или членов агрегата, или меньше символов в строковом литерале, используемом для инициализации массива известного размера, чем элементов в массива, остальная часть агрегата должна быть инициализирована неявно так же, как объекты, которые имеют статическую продолжительность хранения ".

aib 28.07.2020 19:43

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

// put values 1-8, then two zeroes
int list[10] = {1,2,3,4,5,6,7,8};

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

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

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

Не могли бы вы добавить пример использования memset для инициализации массива?

Sopalajo de Arrierez 03.05.2019 23:21

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);.

Benson 03.09.2011 23:44

Как бы вы использовали memset для инициализации массива int некоторым значением больше 255? memset работает только в том случае, если размер массива байтовый.

Matt 16.09.2011 21:03

@Benson: Вы не можете заменить приведенный выше код на memset на платформах, где sizeof (int)> sizeof (char). Попробуй это.

ChrisWue 03.04.2012 23:16

Если массив представляет собой 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} };

Praveen Gowda I V 20.04.2012 16:51

Нет. Вы опускаете самое сокровенное измерение, что недопустимо. Это приведет к ошибке компилятора.

Frank Szczerba 20.04.2012 20:22

И инициализаторы, и вывод длины были введены в C99.

Palec 06.01.2014 00:55

@Palec: Нет - вывод длины был в C со времен предстандартного C (с тех пор, как было опубликовано K&R 1st Edition, и, вероятно, некоторое время до этого). Назначенные инициализаторы были новыми в C99, но в нем не используются назначенные инициализаторы.

Jonathan Leffler 15.02.2017 01:25

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

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?

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

Если ваш компилятор - 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 15.03.2013 17:43

@abhi То, что вы пытаетесь сделать, - это не инициализация, а назначение, этот синтаксис нельзя использовать в такой ситуации, вам будет лучше использовать memset()

qrdl 16.03.2013 16:15

@qrdl спасибо за ответ .. так что в основном для динамического распределения я не могу использовать эту технику. правильный?

abhi 16.03.2013 16:24

И этот синтаксис приводит к огромному увеличению размера файла скомпилированных двоичных файлов. Для N = 65536 (вместо 1024) размер моего двоичного файла увеличивается с 15 КБ до 270 КБ !!

Cetin Sert 28.03.2013 19:15

Компилятор @CetinSert должен добавить 65536 int в статические данные, что составляет 256 КБ - именно такое увеличение размера, которое вы наблюдали.

qrdl 29.03.2013 13:53

@qrdl, почему вы не упомянули об этом в своем ответе?

Cetin Sert 29.03.2013 15:14

@CetinSert Почему я должен? Это стандартное поведение компилятора, не предназначенное для определенных инициализаторов. Если вы статически инициализируете 65536 int, например int foo1 = 1, foo2 = 1, ..., foo65536 =1;, вы получите такое же увеличение размера.

qrdl 30.03.2013 00:48

еще лучше: "int array [] = {[0 ... 1023] = 5}", размер массива будет автоматически установлен на 1024, его проще и безопаснее изменять.

Francois 11.04.2013 13:19

@Francois или bool array[][COLS] = { [0...ROWS-1][0...COLS-1] = true} для двумерного массива, хотя я не уверен, что это более читабельно, чем полная форма.

g33kz0r 13.04.2013 10:59

Я подумал, что когда вы говорите gcc, это также относится и к g++.

mr5 13.12.2013 08:12

Зачем нужно добавлять, 65536 int? Разве вы не указываете его размер 1024?

AlphaGoku 18.02.2019 08:38

@AkshayImmanuelD Пожалуйста, прочтите обсуждение с Цетином Сертом с самого начала.

qrdl 18.02.2019 10:39

Есть ли способ сделать что-то подобное для структур? Если да, ответьте здесь: stackoverflow.com/questions/61240589/….

Gabriel Staples 30.04.2020 21:47

@qrdl Может ли g ++ использовать этот метод?

John 17.01.2021 08:40

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

#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) действителен.

Chris Lutz 14.10.2009 03:58

Не работает. Инициализируются только первые два, остальные не инициализируются. Я использую GCC 4.0 в Mac OS X 10.4.

dreamlax 14.10.2009 04:22

Это вызывает неопределенное поведение, поскольку исходные данные во втором memcpy() перекрываются с целевым пространством. С наивной реализацией memcpy() он может работать, но не требуется, чтобы система заставляла его работать.

Jonathan Leffler 15.02.2017 02:10

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

#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 - более элегантный способ выразить это.

u0b34a0f6ae 14.10.2009 14:41

Конечно, memset () - это то, что вам нужно. Я понял, что OP искал альтернативу.

mouviciel 14.10.2009 15:31

Если данные должны быть доступными для ПЗУ, memset использовать нельзя.

Prof. Falken 05.07.2010 13:24

Препроцессор фактически сгенерирует код из #defines. Чем больше размер массива, тем больше размер исполняемого файла. Но однозначно + за идею;)

Leonid 03.10.2010 16:31

memset инициализируется символом. Его нельзя использовать для инициализации массива int до значения типа 42 .. Значение 0 можно использовать для инициализации до нуля. значение -1 можно использовать для инициализации массива в -1.

EvilTeach 08.05.2011 06:45

@AmigableClarkKant, что вы имели в виду под "ROM-совместимым"?

Alcott 08.02.2012 05:44

@Alcott, на старых компьютерах и все еще во многих встроенных системах код в конечном итоге помещается в EPROM или ПЗУ. ПЗУ-способный также стал обозначать во встроенных системах «код, помещенный во флэш-память», потому что он имеет примерно те же последствия, а именно, что память не может быть записана во время выполнения. Т.е. memset или любые другие инструкции по обновлению или изменению памяти использовать нельзя. Константы, тем не менее, могут быть выражены и записаны во флэш-память или записаны в ПЗУ перед запуском программы.

Prof. Falken 08.02.2012 12:49

(Если флэш-память не используется как обычная файловая система, скажем, в Linux или Windows, и в этом случае флэш-память используется так же, как жесткий диск.) @Alcott.

Prof. Falken 08.02.2012 12:55

@ u0b34a0f6ae: имейте в виду, что вы можете использовать этот метод также, если VAL_1X не одно целое число, а список. Подобно состояниям Amigable, это также путь для встроенных систем, где вы хотите определить значения инициализации EEPROM или флэш-памяти. В обоих случаях нельзя использовать memset().

Martin Scharrer 05.02.2013 13:01

@mouviciel - вопрос: включен ли индекс массива в ваш пример по какой-либо причине? то есть в моем компиляторе ANSI C int myArray[] = { VAL_32X, VAL_16X, VAL_4X, VAL_1X }; работает нормально. Я просто не уверен, есть ли тонкий недостаток в том, что не используется явное значение индекса. +1 за ваш ответ.

ryyker 12.09.2013 22:28

"VAL_64X ... где-то определен ... 42. Подождите? Что это должно делать?" Если мы когда-нибудь будем работать вместе, пожалуйста, просто используйте несколько дополнительных строк кода и сделайте их достаточно глупыми, чтобы кто-то вроде меня мог понять :)

original_username 19.04.2014 17:51

Вы можете легко обобщить это с помощью #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) }; - имена макросов обсуждаются.

Jonathan Leffler 15.02.2017 01:22

@JonathanLeffler Это отличное расширение! Вы не возражаете, если я добавлю это к своему ответу?

mouviciel 15.02.2017 10:03

Получите это! : D - Да, во что бы то ни стало пользуйтесь.

Jonathan Leffler 15.02.2017 10:04

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

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[] = { ... };, не так ли?

Jonathan Leffler 29.04.2012 10:29

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

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

Для элементов 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.

RS1980 17.03.2016 14:37

Как и в случае с любым кодом для тестирования производительности, вам нужно быть предельно осторожным. Добавление цикла для выполнения кода синхронизации 10 раз (и удвоение размера массива до 20 МБ) показывает - для меня при работе на MacBook Pro с macOS Sierra 10.12.3 и с использованием GCC 6.3.0 - что в первый раз, используя цикл занимает около 4600 мкс, а код memfill() - около 1200 мкс. Однако на последующих итерациях цикл занимает около 900–1000 мкс, в то время как код memfill() занимает 1000–1300 мкс. На первую итерацию, вероятно, влияет время заполнения кеша. Поменяйте местами тесты, и memfill() будет медленным с первого раза.

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

пример: 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(...).

Francis Cugler 28.01.2018 22:35

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

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

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

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

Andy 10.02.2017 00:48

Совершенно бесполезен для большой статической таблицы поиска внутри функции, вызываемой много раз.

Martin Bonner supports Monica 21.02.2018 13:28

... не помните, что статические таблицы поиска внутри функций являются частью исходного вопроса - пусть это будет проще. Тем не менее, @Community, вероятно, справился с этим.

JWDN 16.02.2019 19:24

#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, но указывать порядок копирования снизу вверх или сверху вниз в случае перекрытия, но это не так.

supercat 30.01.2020 19:14

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

Mike 01.02.2020 01:07

Это эквивалентно коду в другом отвечать - и ошибочно. Использование memmove() не работает.

Jonathan Leffler 29.02.2020 21:47

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

И т.п.

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

Jonathan Leffler 01.03.2020 02:16

Если размер массива известен заранее, можно использовать макрос препроцессора 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

Cassandra S. 10.01.2021 14:59

Меня смутил int myArray[10] = { 0 }. Я думал, что это можно применить к любым другим константам. Но этого не произошло. Ваше решение помогает.

codexplorer 14.01.2021 06:44

Другие вопросы по теме