Як ініціалізувати всіх членів масиву на одне значення?


968

У мене великий масив в C (не C ++, якщо це має значення). Я хочу ініціалізувати всіх членів одного значення.

Я міг би поклятися, що колись знав простий спосіб зробити це. Я міг би використати memset()у своєму випадку, але чи не існує способу зробити це, що вбудовано прямо у синтаксис С?


16
Жоден з відповідей поки що не згадує позначену нотацію ініціалізатора, що можливо для 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.
Джонатан Леффлер

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

memset () може допомогти, але залежить від значення.
Нік

2
memset()конкретна дискусія: stackoverflow.com/questions/7202411/… Я думаю, що це працює лише для 0.
Ciro Santilli 冠状 病毒 审查 六四 事件 法轮功

Відповіді:


1238

Якщо це значення не дорівнює 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" не обов'язково означає "all-bits-zero", тому використання вищевказаного є кращим і портативнішим, ніж memset (). (Значення з плаваючою комою будуть ініціалізовані до +0, покажчики на нульове значення тощо)


27
Читаючи стандарт C ++, ви також можете робити масив int [10] = {}; до нуля ініціалізації. У мене немає стандарту С, щоб перевірити, чи дійсно це і C.
workmad3

54
Дивлячись на розділ 6.7.8 Ініціалізація стандарту C99, не видається, що пустий список ініціалізатора дозволений.
Джонатан Леффлер

7
C99 має багато приємних функцій для ініціалізації структури та масиву; єдина особливість, яку він не має (але Fortran IV, 1966, мав) - це спосіб повторити певний ініціалізатор для масиву.
Джонатан Леффлер

8
@CetinSert: Що ти означає, що це не працює? Це робить саме те, що ця відповідь каже, що вона повинна робити. Це не робить те, що пише коментар у вашому коді, але цей коментар невірний.
Бенджамін Ліндлі

9
@CetinSert: Ти єдиний, хто в цьому коментарі стверджував, що всі елементи будуть встановлені на -1. Ця відповідь справедливо стверджує, що всі неуточнені елементи встановлюються на нуль. Результати вашого коду відповідають цій заяві.
Бенджамін Ліндлі

394

Якщо ваш компілятор GCC, ви можете використовувати наступний синтаксис:

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

Ознайомтеся з детальним описом: http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Designized-Inits.html


12
І цей синтаксис спричиняє величезне збільшення розміру файлу складених бінарних файлів. Для N = 65536 (замість 1024) мої двійкові скачки розміром від 15 КБ до 270 КБ !!
Cetin Sert

50
@CetinSert Compiler повинен додати 65536 intс до статичних даних, що становить 256 К - саме збільшення розміру, яке ви спостерігали.
qrdl

15
@CetinSert Чому я повинен? Це стандартна поведінка компілятора, не специфічна для призначених ініціалізаторів. Якщо ви статично ініціалізуєте 65536 intс, як і int foo1 = 1, foo2 = 1, ..., foo65536 =1;ви отримаєте таке ж збільшення розміру.
qrdl

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

4
@Francois або для 2d масиву, bool array[][COLS] = { [0...ROWS-1][0...COLS-1] = true}хоча я не впевнений, що це читабельніше, ніж повна форма.
g33kz0r

178

Для статичної ініціалізації великого масиву з тим самим значенням без безлічі копій-вставок можна використовувати макроси:

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

назви макросів підлягають обороту.


12
Я б вважав це лише в крайніх випадках, безумовно, мемсет є більш елегантним способом висловити це.
u0b34a0f6ae

47
Якщо дані мають бути спроможними для ПЗУ, мемсет не можна використовувати.
Контракт професора Фолкена порушено

9
Препроцесор фактично генерує код з #defines. Із більшими розмірами масиву розмір виконуваного файлу зростатиме. Але напевно + за ідею;)
Леонід

7
@Alcott, на старих комп'ютерах та на багатьох вбудованих системах код з часом розміщується в EPROM або ROM . ROM-можливість також у вбудованих системах означає "код, поставлений у спалах", оскільки він має приблизно такі самі наслідки, а саме те, що пам'ять не може бути записана під час виконання. Тобто мемсет або будь-яка інша інструкція щодо оновлення або зміни пам'яті використовувати не можна. Константи, однак, можуть бути виражені і прошиті або прострочені ПЗУ до запуску програми.
Контракт професора Фолкена порушив

4
@ u0b34a0f6ae: Майте на увазі, що ви можете використовувати цей метод також, якщо VAL_1Xце не одне ціле число, а список. Як і стан Amigable, це також шлях для вбудованих систем, де потрібно визначити значення init EEPROM або Flash-пам'яті. В обох випадках ви не можете використовувати memset().
Мартін Шаррер

63

Якщо ви хочете переконатися, що кожен член масиву явно ініціалізований, просто опустіть вимір з декларації:

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 IV

10
Ні. Ви опускаєте найпотаємніший вимір, який не дозволений. Це призведе до помилки компілятора.
Франк Щебра

4
І ініціалізатори, і довжина висновку були введені в C99.
Палець

3
@Palec: Немає тривалості висновку було в C з часів попереднього стандарту C (з моменту опублікування першого видання K&R і, мабуть, до цього часу). Позначені ініціалізатори були новими в C99, але для цього не використовуються призначені ініціалізатори.
Джонатан Леффлер

53

Я побачив код, який використовував цей синтаксис:

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

Де це стає особливо корисним, якщо ви створюєте масив, який використовує enums як індекс:

enum
{
    ERR_OK,
    ERR_FAIL,
    ERR_MEMORY
};

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

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

Це підтримує порядок, навіть якщо вам трапляється записати деякі значення перерахунків.

Більше про цю техніку можна дізнатися тут і тут .


8
Це синтаксис ініціалізатора C99, вже охоплений деякими іншими відповідями. Ви могли б корисно вносити декларацію char const *array[] = { ... };або навіть char const * const array[] = { ... };, чи не так?
Джонатан Леффлер

22
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...

випадок зміни розміру масиву.


12
Для запису, це в основному лише повільніша, більш багатослівна версіяmemset(myArray, VALUE, ARRAY_SIZE);
Бенсон

18
Як би ви використовували memset для ініціалізації масиву int до деякого значення, що перевищує 255? memset працює лише в тому випадку, якщо масив має розмір байтів.
Метт

21
@Benson: Ви не можете замінити вищевказаний код мемсетом на платформах, де sizeof (int)> sizeof (char). Спробуй це.
ChrisWue

13

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

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

Якщо дійсно важливо, щоб масив був статично оголошений, я б написав програму, щоб написати програму для мене і зробити її частиною процесу збирання.


Чи можете ви, будь ласка, додати якийсь приклад використання цього memsetзасобу для ініціалізації масиву?
Sopalajo de Arrierez

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-розширення

Позначені ініти

Тоді поставте питання: Коли можна використовувати розширення C?

Зразок коду, наведений вище, знаходиться у вбудованій системі і ніколи не побачить світло іншого компілятора.


6

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

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

5

Якщо масив є int або що-небудь з розміром int або розмір вашого mem-pattern відповідає точним часом в int (тобто всі нулі або 0xA5A5A5A5), найкращим способом є використання memset () .

В іншому випадку викликайте memcpy () в циклі, що переміщує індекс.


5

Трохи відповідь язиком у щоку; написати заяву

array = initial_value

на улюбленій мові, що підтримує масив (у мене є Fortran, але є багато інших), і прив’яжіть її до свого коду С. Ви, мабуть, хочете, щоб це було зовнішньою функцією.


4

Існує швидкий спосіб ініціалізації масиву будь-якого типу із заданим значенням. Він дуже добре працює з великими масивами. Алгоритм такий:

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

Для 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;
}

2
Вибачте, але це неправда. Можливо, ви забули ввімкнути оптимізацію компіляції під час тестів (протестовано в режимі налагодження?). Якщо я тестую це, цикл майже завжди на 50% швидший, ніж memfill ("завжди" через деякі тремтіння навантаження на моїй машині). І за допомогою memset (a, 0, sizeof (a)); навіть удвічі швидше, ніж циклічне заповнення.
RS1980

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

2

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

#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

4
<iostream>Недійсний, Cоскільки std::cout, std::cinтощо, є частиною std::namespaceі Cне підтримує namespaces. Спробуйте використовувати <stdio.h>для printf(...)замість.
Френсіс Куглер

2

Виконуючи всю балаканину, коротка відповідь полягає в тому, що якщо ввімкнути оптимізацію під час компіляції, ви не зробите краще цього:

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

Доданий бонус: код насправді розбірливий :)


7
Питання спеціально задало ініціалізацію. Це явно не ініціалізація, а призначення, виконане після ініціалізації. Це може бути зроблено негайно, але це все ще не ініціалізація.
Енді

Цілком не корисно для великої статичної таблиці пошуку всередині функції, яка називається багато разів.
Мартін Боннер підтримує Моніку

... не згадуйте статичні таблиці пошуку всередині функцій, що є частиною оригінального питання - нехай це буде просто. Це сказало, @Community, ймовірно, прибив це.
JWDN

1
  1. Якщо ваш масив оголошений статичним або глобальним, всі елементи масиву вже мають значення за замовчуванням 0.
  2. Деякі компілятори встановлюють параметр масиву за замовчуванням 0 в режимі налагодження.
  3. Легко встановити за замовчуванням 0: int масив [10] = {0};
  4. Однак для інших значень ви використовуєте memset () або цикл;

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


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


0

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


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


0

Для затримки ініціалізації (тобто ініціалізації конструктора члена класу) врахуйте:

int a[4];

unsigned int size = sizeof(a) / sizeof(a[0]);
for (unsigned int i = 0; i < size; i++)
  a[i] = 0;

0

Я знаю, що в оригінальному питанні явно згадується 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)


-1

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

#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


1
Мені сумнівно, чи це рішення. Я не впевнений, чи sizeof(void)дійсний він.
Кріс Лутц

3
Це не працює. Ініціалізуються лише перші два, решта - неініціалізовані. Я використовую GCC 4.0 на Mac OS X 10.4.
dreamlax

Це викликає невизначене поведінку, оскільки вихідні дані у другій memcpy()збігаються з місцем призначення. При наївному здійсненні memcpy()це може працювати, але не потрібно, щоб система змушувала його працювати.
Джонатан Леффлер

-1

Ще в той день (і я не кажу, що це гарна ідея) ми встановимо перший елемент, а потім:

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

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


Це не буде надійно працювати. IMHO, Стандарт повинен був передбачати функції, які були подібні, memcpyале вказані замовлення на копіювання знизу вгору чи згори вниз у разі перекриття, але це не так.
supercat

Як я вже говорив, це було лише те, що ми зробили, що не працюватиме надійно, але тоді ми були більш зосереджені на ефективності, ніж на униканні недокументованих функцій. Хоча ефективніше копіювати пам'ять вперед, в специфікації немає нічого, що б сказало, що вона не може скопіювати її назад, у довільному порядку або розділити її на кілька потоків. memmove () забезпечує можливість копіювання без сутичок.
Майк

Це еквівалентно коду в іншій відповіді - і хибно. Використання memmove()не змушує його працювати.
Джонатан Леффлер

-2

Якщо ви маєте на увазі паралельно, я думаю, що оператор комами, коли він використовується в поєднанні з виразом, може зробити це:

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 / тощо, щоб виділити об'єкту фіксовану область зберігання:

int *array = malloc(sizeof(int)*numberOfListElements/Indexes);

і отримати доступ до членів:

*(array + index)

І т.д.


Оператор комами номінально гарантує оцінку зліва направо. Якщо в виразах немає побічних ефектів, тоді можливо паралелізувати операції, але компілятору це було б незвично.
Джонатан Леффлер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.