изменение значения указателя
и снова привет! продолжаю изучение указателей, и на сей раз задался вопросом: что если представить ситуацию, где указатель ссылается на переменную, а после над этим же указателем провести операцию инкремента или декремента, то куда и на что он будет указывать? решил сам написать код, значения весьма странные, но думаю это тоже связано с битовым представлением числа, как мне подсказали в прошлый раз
#include<stdlib.h>
#include<stdio.h>
#include<math.h>
int main(void) {
int a = 1;
float b = 2;
double c = 3;
int* p1 = &a;
float* p2 = &b;
double* p3 = &c;
p1 = (int*)p2;
p3 = (double*)p2;
p1++;
p3--;
printf("p1=%p\tp2=%p\tp3=%p\n", p1, p2, p3);
printf("*p1=%d\t\t*p2=%f\t*p3=%lf\n",
*p1, *p2, *p3);
p1 -= 4;
p3 = (double*)&a - 1;
printf("p1=%p\tp2=%p\tp3=%p\n", p1, p2, p3);
printf("*p1=%d\t*p2=%f\t*p3=%lf\n",
*p1, *p2, *p3);
return 0;
}
Буду также рад и источникам с информацией о вопросе!
Ответы (1 шт):
Привет) Инкремент и декремент указателя, соответственно, увеличивает и уменьшает содержащийся в нём адрес на величину, равную размеру типа данных, на которые он ссылается. Об этом написано в любом учебнике по C/C++, так что не совсем понятно, в чём возник вопрос. Но всё равно проясню.
Возможны следующие варианты.
Указатель ссылается на элемент массива. Тогда после инкремента он будет ссылаться на следующий элемент массива. Если он перед этим ссылался на последний элемент, то после инкремента он станет указывать за пределы массива - в этом случае обращение к содержимому по этому указателю вызовет неопределённое поведение (Undefined Behavior, UB). Аналогично для декремента - будет указывать на предыдущий элемент. Если до декремента указатель ссылался на первый элемент, то после он опять таки вывалится за пределы массива, только уже с другой стороны - и снова будет UB при обращении по такому указателю.
Указатель ссылается на одиночную переменную или объект. В этом случае инкремент, либо декремент приведёт к тому, что этот указатель будет ссылаться за пределы переменной или объекта. И обращение по нему вызовет UB.
Указатель ссылается на неизвестно что (например, он не был проинициализирован и содержит мусор). Чтение либо запись данных через этот указатель, как нетрудно догадаться, вызовет UB.
А теперь, исходя из выше написанного, ответы на ваши вопросы:
- Вопрос: на что указывают указатели? Ответ: на что-то такое, что вы не контролируете. Если указатель указывал на переменную
a, а вы сделали ему инкремент, то он будет указывать на что-то заa. По чистой случайности это могут оказаться данные переменнойb. А может это будут байты выравнивания между переменнойaи какой-нибудь другой переменной (вовсе не обязательно, что это будетb). А может за пределами переменнойaвообще ничего не быть - пустая страница виртуальной памяти без физического отображения, в этом случае при попытке прочитать что-нибудь оттуда ваша программа просто закрэшится с ошибкой "Access violation..." или что-то в этом роде. В этом вся суть неопределённого поведения. - Вопрос: что это за значения? Ответ: неопределённые (см. ответ выше).
- Вопрос: почему они такие? Ответ: потому что UB. Неопределённое поведение, которого при написании программ, следует избегать любой ценой.