Другие языки программирования и технологии

Почему работает этот код?

#include <iostream>
#include <conio.h>

using namespace std;

int main()
{

// указатель на массив из 2-х объектов
int * a = new int[2];

a[0] = 0;
a[1] = 1;

// Вышли за предел массива
a[2] = 2;
a[3] = 3;
a[4] = 4;

// Работает
cout << a[4]; // 4

_getch();
return 0;
}

1) Почему код работает, хотя мы и вышли за предел массива?
2) Почему присваиваем так a[1] = 1, а не *a[1] = 1 ?
1) Код работает, но неопределенно, это UB. Может, заработает, а может, нет - никто не гарантирует.
2) Потому что a[1] имеет тип int, и разыменовывать его бессмысленно. Запоминаем: a[ b] - синоним для *(a+b).
Виталий Должиков
Виталий Должиков
94 727
Лучший ответ
1) потому что дальше тоже есть память. С не проверяет выход за границы отведенной программистом памяти, он просто вычисляет адрес и пишет туда или читает оттуда. Естественно, работает такой программы будет зависеть от того, что лежит там, куда она залезла. Может, ничего, а может, совсем другая переменная, которая непрдвиденно изменится.
2) потому что операция квадратные скобки (а это именно операция, как и +: + и т. д. и может даже переопределяться) в большинстве случаев эквивалентна адресной арифметике, то есть a[1] эквивалентно *(a+1). Не всегда, но часто.
Тыщу лет назад учил и си и ассемблер. Я так понимаю, ты объявляешь указатель на область данных, а дальше только задаёшь смещение относительно этого адреса, поэтому можешь выйти куда-то. Но как бы ты ненароком не залез в область другой переменной. Тут лучше спросить у си-программистов, которых не факт, что встретишь на этом сайте.
А по поводу звёздочи, ты ж уже объявил указатель, дальше просто помни, что a - это он.
Юра Якимик
Юра Якимик
50 825
1) Твои данные пишутся поверх каких-то других данных и затирают их, поведение программы становится непредсказуемым.
2) Между массивами и указателями в Си довольно размытая граница, в частности каждый указатель можно индексировать как массив.