﻿# Выход за границу массива

Выход за границу массива \(Array index out of bounds\) — это частный случай [переполнения буфера](https://pvs-studio.ru/ru/blog/terms/0067/)\. Ошибка возникает, если индекс, с помощью которого обращаются к элементам массива, превышает допустимое значение\. При этом идёт обращение за границы массива, что является [неопределенным поведением](https://pvs-studio.ru/ru/blog/terms/0066/)\. Это возможно из\-за того, что в языках программирования С и С\+\+ нет строгого контроля выхода за границы массива: наличие проверок зависит от используемых инструментов и их реализации\. 

Диагностировать выход за границы массива можно с помощью инструментов [статического](https://pvs-studio.ru/ru/blog/terms/0046/) или [динамического](https://pvs-studio.ru/ru/blog/terms/0070/) анализа кода\. Эти диагностики очень актуальны, поскольку такие ошибки могут проявляться не сразу\. Работоспособность программы будет зависеть от версии компилятора, операционной системы, затронутых данных и т\.д\.

Рассмотрим данную ошибку на примерах, найденных в коде реальных Open Source проектов с помощью статического анализатора [PVS\-Studio](https://pvs-studio.ru/ru/pvs-studio/)\.

Проект Dumb \(динамическая универсальная музыкальная библиотека\):

```cpp
struct IT_SAMPLE
{
  ....
  unsigned char filename[14];
  ....
};

static int it_riff_dsmf_process_sample(
  IT_SAMPLE * sample, const unsigned char * data, int len)
{
  int flags;
  memcpy( sample->filename, data, 13 );
  sample->filename[ 14 ] = 0;
  ....
}
```

Массив _filename_ состоит из 14 элементов, однако в функции _it\_riff\_dsmf\_process\_sample_ идёт обращение к 14\-му элементу, который находится за границами массива\. Такую ошибку часто допускают, забывая, что индексация массивов в языках С и С\+\+ начинается с нуля и заканчивается значением на единицу меньше размера массива \(в данном случае — 13\)\.

Рассмотрим ещё одну подобную ошибку\. Проект Wolfenstein 3D \(компьютерная игра, разработанная компанией id Software\):

```cpp
typedef struct bot_state_s
{
  ...
  char teamleader[32]; //netname of the team leader
  ...
}  bot_state_t;

void BotMatch_StartTeamLeaderShip(
  bot_state_t *bs, bot_match_t *match)
{
  ...
  bs->teamleader[sizeof( bs->teamleader )] = '\0';  //< =
  ...
}
```

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

Также здесь стоит сделать ремарку, что выбранный разработчиками способ доступа к последнему элементу не является надежным, т\.к\. работает только если массив содержит элементы размером 1 байт \(char, unsigned char и т\.п\.\)\. Более правильный способ получения индекса последнего элемента выглядит так:

```cpp
const size_t lastPos = sizeof(bs->teamleader) / 
                       sizeof(bs->teamleader[0]) - 1;
bs->teamleader[lastPos] = '\0';
```

Здесь мы получаем общий размер массива в байтах и делим его на размер первого элемента, тем самым получая количество элементов в массиве\. В конце остаётся только вычесть единицу\. Полученное значение и будет индексом последнего элемента в массиве\.

На самом деле, даже указанное выше исправление не является хорошим\. Если вы пишите именно на С\+\+, то для вас существуют более безопасные и удобные способы работы с массивами\. Подробнее мы рассмотрели их в статье "[Как не надо проверять размер массива в С\+\+](https://pvs-studio.ru/ru/blog/posts/cpp/1112/)", а именно в разделе "[Современный C\+\+: правильное вычисление количества элементов в массивах и контейнерах](https://pvs-studio.ru/ru/blog/posts/cpp/1112/#ID50D694CCBE)"\.

Другие примеры таких ошибок, найденных в Open Source проектах с помощью статического анализатора PVS\-Studio, можно посмотреть [здесь\.](https://pvs-studio.ru/ru/blog/examples/v557/)