Как мне инициализировать массивы более эффективно, чем цикл for? c

#c #arrays #initialization

#c #массивы #инициализация

Вопрос:

В настоящее время я инициализирую массивы, создавая циклы for и устанавливая arr[I] = 0 . Есть ли другой способ сделать это более эффективно?

 Student::Student(){
    
    name = "John";
    for(int i = 0; i<sizeof(id);  i)
    {
        id[i] = '0';
    }
    for(int i = 0; i<sizeof(testScore);  i)
    {
        testScore[i] = 0;
    }
    avgScore = 100;
    grade = 'A';
    
}
  

Комментарии:

1. Привет! Что это за язык программирования? Пожалуйста, добавьте его в теги.

2. Извините, это cpp.

3. memset, calloc, …

4. Вы знаете о std::fill ? Или это может быть более эффективным в использовании memset .

5. Не беспокойтесь. Это микрооптимизация. Распечатайте язык ассемблера. Увеличьте уровень оптимизации, затем распечатайте язык ассемблера. Сделайте это для всех уровней оптимизации.

Ответ №1:

Вы можете попробовать нулевую инициализацию.

пример:

     int arr1[12] = {}; // values: 000000000000
    std::array<int, 5> arr2 = {}; // values: 00000
  

Таким образом, вы можете пропустить цикл for и получить более чистый код.

Комментарии:

1. Более эффективным решением является не инициализация массива при построении; заполните массив во время процесса ввода, например std::cin . Нулевая инициализация может в конечном итоге привести к дублированию записи в массив.

Ответ №2:

Развертывание цикла

Вот пример развертывания цикла:

 const int capacity = sizeof(id) / sizeof(id[0]);
const int fill_value = 0; // hopefully compiler assigns to a register.
int i = 0;
if (capacity amp; 3 == 0)
{  
    for (i = 0; i < capacity; i  = 4)
    {
        id[i   0] = fill_value;
        id[i   1] = fill_value;
        id[i   2] = fill_value;
        id[i   3] = fill_value;
    }
}
// initialize remaining slots
for (; i < capacity;   i)
{
    id[i] = 0;
}
  

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

Идея развертывания цикла заключается в выполнении большего количества инструкций по передаче данных подряд перед инструкцией перехода или перехода. Процессору не нравятся инструкции перехода. Инструкции перехода заставляют процессор решать, перезагружать кэш команд или нет; это занимает время, которое может быть потрачено на выполнение инструкций данных. Развернутый цикл также выполняет меньше сравнений, чем исходный цикл. Опять же, инструкции сравнения занимают время, которое можно было бы потратить на выполнение инструкций данных.

Нет цикла

Цель состоит в том, чтобы минимизировать ветвление и сравнение.
Если ваш массив небольшой (по вашему определению), вы можете назначить слоты без цикла:

 int * p = amp;id[0];
const int fill_value = 0;
*p   = fill_value;  *p   = fill_value; *p   = fill_value; *p   = fill_value;  
*p   = fill_value;  *p   = fill_value; *p   = fill_value; *p   = fill_value;  
*p   = fill_value;  *p   = fill_value; *p   = fill_value; *p   = fill_value;  
*p   = fill_value;  *p   = fill_value; *p   = fill_value; *p   = fill_value;  
*p   = fill_value;  *p   = fill_value; *p   = fill_value; *p   = fill_value;  
  

Операция увеличения указателя и переноса по-прежнему выполняется быстрее, чем процесс сравнения процессором значения или изменения счетчика программы (ветви).