Адреса в языке Си
Программа 1
#include <stdio.h>
int main()
{
int c = 12;
int *a = &c + 11;
printf("%d", *a);
return 0;
}
Программа 2
#include <stdio.h>
int main()
{
int *a;
printf("%d", *a);
return 0;
}
В первой программе выведется некоторое значение, во второй segfault. Так же первая программма упадет если отступить на большее число например &c + 11111
Вопрос
Как это грамотно объяснить? Буду признателен за подробный ответ
Изменено: я понимаю что это ub в обоих случаях, но мне все еще нужен более подробный ответ
Ответы (2 шт):
В обоих случаях вы ссылаетесь на память, не выделенную для использования программой.
В первом случае это память, отстоящая на 11 переменных int
от c
— но у вас ведь c
не массив, так что это какая-то память в стеке.
Во втором a
вообще имеет неопределенное значение, вы обращаетесь к памяти неизвестно где.
В любом случае и то, и другое — неопределенное поведение. А как именно себя проявит неопределенность — вопрос тоже неопределенный :)
В обоих случаях проблемы случаются еще до обращения по кривым указателям.
В первом случае в выражении &c + 11
смещение имеет недопустимую величину. Когда адресная арифметика применяется к указателю на отдельный объект, то он рассматривается как массив из 1 элемента и прибавить к такому указателю можно либо 0
, что не меняет значения указателя, либо 1
, получив указатель на объект "следующий" за данным. Во втором случае полученный указатель может быть использован только для сравнения на равенство с исходным. Ну а смещение на 11
является Неопределенным Поведением, что (среди прочего) означает, что полученный указатель не обязательно будет указывать на память, отстоящую на 11 переменных int
от c
или вообще указывать куда-то на стек, как то утверждается в другом ответе.
Во втором случае происходит обращение к неинициализированной переменной a
, что тоже является Неопределенным Поведением. Причем ещё до обращения к объекту, на который указывает указатель, именно чтение самого значения указателя.