Функция calloc()

Вместо функции malloc() можно воспользоваться функцией calloc(). Прототип функции:

#include <cstdlib> /* или #include <stdlib.h> */
void *calloc(size_t count, size_t elem_size);

В первом параметре функция calloc() принимает количество элементов, а во втором — размер одного элемента. Если память выделить не удалось, то функция возвращает нулевой указатель. Все элементы будут иметь значение 0.

Используя функцию calloc(), следующую инструкцию из листинга 3.18:

int *p = (int *) std::malloc(ARR_SIZE * sizeof(int));

мы можем записать так:

int *p = (int *) std::calloc(ARR_SIZE, sizeof(int));

В качестве примера использования функции calloc() создадим двумерный массив (листинг 3.19). Для этого нам нужно создать массив указателей и в каждом элементе массива сохранить адрес строки. Память для каждой строки нужно выделить дополнительно.

Листинг 3.19. Динамическое выделение памяти под двумерный массив

#include <iostream>
#include <cstdlib>
#include <process.h>

int main() {
   const int ROWS = 2;    // Количество строк
   const int COLUMNS = 4; // Количество столбцов
   int i = 0, j = 0;
   // Создаем массив указателей
   int **p = (int **) std::calloc(ROWS, sizeof(int*));
   if (!p) exit(1);                // Выходим при ошибке
   // Добавляем строки
   for (i = 0; i < ROWS; ++i) {
      p[i] = (int *) std::calloc(COLUMNS, sizeof(int));
      if (!p[i]) exit(1);          // Выходим при ошибке
   }
   // Нумеруем элементы массива
   int n = 1;
   for (i = 0; i < ROWS; ++i) {
      for (j = 0; j < COLUMNS; ++j) {
         p[i][j] = n++;
         // *(*(p + i) + j) = n++;
      }
   }
   // Выводим значения
   for (i = 0; i < ROWS; ++i) {
      for (j = 0; j < COLUMNS; ++j) {
         std::cout << p[i][j] << ' ';
         // std::cout << *(*(p + i) + j) << ' ';
      }
      std::cout << std::endl;
   }
   // Освобождаем память
   for (int i = 0; i < ROWS; ++i) {
      std::free(p[i]);
   }
   std::free(p);
   p = nullptr;                         // Обнуляем указатель
   return 0;
}

Обратите внимание: при возвращении памяти вначале освобождается память, выделенная ранее под строки, а лишь затем освобождается память, выделенная ранее под массив указателей.

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

Строки в памяти могут быть расположены в разных местах, что не позволяет эффективно получать доступ к элементам двумерного массива. Чтобы доступ к элементам сделать максимально быстрым, можно представить двумерный массив в виде одномерного массива (листинг 3.20).

Листинг 3.20. Представление двумерного массива в виде одномерного

#include <iostream>
#include <cstdlib>
#include <process.h>

int main() {
   const int ROWS = 2;    // Количество строк
   const int COLUMNS = 4; // Количество столбцов
   int i = 0, j = 0;
   int *p = (int *) std::calloc(ROWS * COLUMNS, sizeof(int));
   if (!p) exit(1);                // Выходим при ошибке
   // Нумеруем элементы массива
   int n = 1;
   for (i = 0; i < ROWS; ++i) {
      for (j = 0; j < COLUMNS; ++j) {
         *(p + i * COLUMNS + j) = n++;
      }
   }
   // Выводим значения
   for (i = 0; i < ROWS; ++i) {
      for (j = 0; j < COLUMNS; ++j) {
         std::cout << *(p + i * COLUMNS + j) << ' ';
      }
      std::cout << std::endl;
   }
   std::free(p);                        // Освобождаем память
   p = nullptr;                         // Обнуляем указатель
   return 0;
}

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

int *p2 = p; // Сохраняем адрес первого элемента
int n = 1;
int count = ROWS * COLUMNS;
for (i = 0; i < count; ++i) {
   *p2 = n++;
   ++p2;
}

Учебник C++ (MinGW-W64)
Учебник C++ (MinGW-W64) в формате PDF

Помощь сайту

ЮMoney (Yandex-деньги): 410011140483022

ПАО Сбербанк:
Счет: 40817810855006152256
Реквизиты банка:
Наименование: СЕВЕРО-ЗАПАДНЫЙ БАНК ПАО СБЕРБАНК
Корреспондентский счет: 30101810500000000653
БИК: 044030653
КПП: 784243001
ОКПО: 09171401
ОКОНХ: 96130
Скриншот реквизитов