C указатели (разница между int и char при использовании указателей), пример ниже? - PullRequest
0 голосов
/ 01 ноября 2018

Я нахожусь в фазе изучения указателей C, я искал в Интернете некоторые коды, использующие указатели, и нашел один код, и я сейчас совершенно сбит с толку.

int x, y;

char *p;

printf("Enter two integers:\n");

scanf("%d%d", &x, &y);

p = (char *)x;

while(--y) 

  p = &p[x];

P - произведение x * y (умножение), и этот код работает нормально. Но если я изменю тип указателя на целое число (int *p и p= (int *)x), это даст мне номер мусора.

Может кто-нибудь объяснить мне, почему в этом случае используется "char" и почему он работает нормально, а не "int" для указателя. И что происходит в «p = &p[x]» (я понятия не имею, как работает эта строка).

1 Ответ

0 голосов
/ 01 ноября 2018

Этот код полагается на неопределенное поведение в отношении арифметики указателей для выполнения простого умножения.

Арифметика указателя корректно определена только в том случае, если указатель указывает на действительный объект и результат арифметики также указывает внутри этого объекта.

Эта первая строка:

p = (char *)x;

Принимает целочисленное значение x, заданное пользователем, и интерпретирует его как указатель на char * Независимо от того, что это значение, скорее всего, не указывает на допустимое местоположение, поэтому любая арифметика на нем является неопределенным поведением. Но на данный момент давайте предположим, что компилятор будет выполнять арифметику, как если бы он указывал на действительный объект, и указатель представлялся одним целочисленным значением.

В теле цикла имеем:

p = &p[x];

Индексация массива здесь в точности эквивалентна:

p = &(*(p + x));

Оператор разыменования и оператор адресации отменяют друг друга, поэтому это эквивалентно:

p = p + x;

При добавлении к указателю он фактически добавляет заданное значение, умноженное на размер указанного типа, вместо непосредственного добавления к значению указателя. Это позволяет нам использовать простую арифметику для указания начала данного элемента массива, а не некоторого смещения в данном элементе массива, если тип больше одного байта. В этом случае указанным типом является char, поэтому x * sizeof(char) добавляется к необработанному значению p. А поскольку sizeof(char) по определению 1, p = p + x просто добавляет x к необработанному значению p.

Теперь посмотрим на полный цикл с переведенным телом:

while (--y)
    p = p + x;

Значение y уменьшается, и проверяется уменьшенное значение, чтобы определить, равно ли оно нулю. Если нет, то тело работает, что добавляет x к p.

Предположим, y равно 1. Он уменьшается до 0, а значение 0 используется как условие для цикла while, который в логическом контексте равен false. Таким образом, цикл не вводится и p имеет значение x. Если y равно 2, цикл будет введен один раз, а p будет равен x + x. Если y равно 3, цикл вводится дважды, поэтому p будет x + x + x.

Таким образом, эффект здесь в том, что p при преобразовании обратно в целое число содержит значение x * y.

Причина, по которой вы получаете другое значение при изменении типа p на int *, заключается в том, как арифметика указателя обрабатывается, как упоминалось ранее. sizeof(int), скорее всего, 4, поэтому p = p + x фактически добавляет x * 4 к необработанному значению p, поэтому результат будет в 4 раза больше.

Повторим, однако, все вышеперечисленное зависит от неопределенного поведения , поскольку p не указывает на допустимый объект. Он может работать на некоторых системах и компиляторах, но он не гарантированно работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...