как здесь работают указатели в c? - PullRequest
0 голосов
/ 02 ноября 2010
#include <stdio.h>

int my_array[] = {1,23,17,4,-5,100};
int *ptr;

int main(void)
{
    int i;
    ptr = &my_array[0];     /* point our pointer to the first
                                      element of the array */
    printf("\n\n");
    for (i = 0; i < 6; i++)
    {
      printf("my_array[%d] = %d   ",i,my_array[i]);   /*<-- A */
      printf("ptr + %d = %d\n",i, *(ptr + i));        /*<-- B */
      printf("ptr + %d = %d\n",i, *ptr++);
      printf("ptr + %d = %d\n",i, *(++ptr));
    }
    return 0;
}

ptr ++ должен печатать значение ptr, чем приращение в нем, в то время как ++ ptr делает 1-е приращение в ptr, чем печатать значение ptr .. но когда я компилирую код, он дает мне тот же результат, что и указатель void.какая польза от этого.

Ответы [ 5 ]

2 голосов
/ 02 ноября 2010

Выражение *ptr++ анализируется как *(ptr++) и оценивается следующим образом:

  1. Получить текущее значение ptr
  2. Разыменование этого значения указателя для получения целочисленного значения
  3. В какой-то момент перед следующей точкой последовательности добавьте 1 sizeof *ptr к ptr.

Это примерно эквивалентно написанию

x = *ptr;
ptr = ptr + sizeof *ptr;

за исключением того, что побочный эффект обновления ptr может произойти в любое время до следующей точки последовательности ( никогда предполагает, что побочные эффекты применяются в определенном порядке); IOW, последовательность может быть

tmp = ptr;
ptr = ptr + sizeof *ptr;
x = *tmp;

В этом случае точка последовательности находится в конце вызова функции printf.

Выражение *(++ptr) анализируется как записанное и оценивается следующим образом:

  1. Получить текущее значение ptr + sizeof *ptr
  2. Отмените значение этого указателя для получения целочисленного значения
  3. В какой-то момент перед следующей точкой последовательности добавьте 1 sizeof *ptr к ptr

что примерно эквивалентно написанию

tmp = ptr + sizeof *ptr;
x = *tmp;
ptr = ptr + sizeof *ptr;

, где, опять же, побочный эффект обновления значения ptr может произойти в любой точке до следующей точки последовательности; IOW, последовательность может быть

tmp = ptr + sizeof *ptr;
ptr = ptr + sizeof *ptr;
x = *tmp;

Вот гипотетическая карта памяти при запуске программы (предположим, 32-битные адреса и 16-битные значения):

Item        Address            0x00  0x01  0x02  0x03
----        --------           ----  ----  ----  ----
my_array    0x08000000         0x00  0x01  0x00  0x17
            0x08000004         0x00  0x11  0x00  0x04
            0x08000008         0xff  0xfb  0x00  0x64
ptr         0x0800000C         0x00  0x00  0x00  0x00
i           0x10008000         0x??  0x??  0x??  0x??

0x?? указывает случайное значение байта. Поскольку ptr объявлено в области видимости файла, оно имеет статический экстент и неявно инициализируется значением NULL. Поскольку i объявлен auto, он не инициализирован и содержит случайный мусор.

После выполнения оператора ptr = &my_array[0] значение ptr равно 0x08000000.

При выполнении строки

printf("ptr + %d = %d", i, *ptr++);

выражение *ptr++ разыменовывает память по адресу 0x08000000, который содержит значение 1, поэтому на выходе получается

ptr + 0 = 1

Побочный эффект оператора ++ обновляет значение с ptr до 0x08000002.

При выполнении строки

printf("ptr + %d = %d, i, *(++ptr));

выражение *(++ptr) задерживает память на 0x08000004, а не 0x08000002, поскольку выражение ++ptr оценивается как ptr + sizeof *ptr. Таким образом, вывод этой строки

ptr + 0 = 17

и побочный эффект оператора ++ обновляет значение с ptr до 0x08000004.

Таким образом, когда вы зацикливаетесь, ваш вывод будет выглядеть как

my_array[0] = 1     /* ptr = 0x08000000 */
ptr + 0 = 1
ptr + 0 = 1         /* ptr = 0x08000002 after */
ptr + 0 = 17        /* ptr = 0x08000004 after */
my_array[1] = 23
ptr + 1 = 4         
ptr + 1 = 4         /* ptr = 0x08000006 after */
ptr + 1 = -5        /* ptr = 0x08000008 after */
2 голосов
/ 02 ноября 2010

Эти строки:

printf("ptr + %d = %d\n",i, *ptr++);
printf("ptr + %d = %d\n",i, *(++ptr));

изменить значение указателя. Таким образом, на каждой итерации вы добавляете 2 смещения сверх вашей текущей позиции i. К тому времени, когда ваш цикл for достигнет 6-й итерации, вы попытаетесь напечатать ячейки памяти от конца массива до где-то 6 (итераций) * 2 (смещения) * 4 (int size) = 48 байтов за пределами.

1 голос
/ 02 ноября 2010

Через несколько раз через этот цикл вы начнете ссылаться на память за концом массива; кроме того, ваша программа выглядит так, как будто имеет смысл.

0 голосов
/ 02 ноября 2010

Во-первых, как указал Игнасио, это весь C-код.Не с ++.C ++ является надмножеством C.

1) Я хочу отметить, что ваш цикл for небезопасен.Потому что вы увеличиваете указатель дважды внутри цикла в каждой итерации.Итак, вы окажетесь за пределами выделенного массива на 4-й итерации.

2) Любые вопросы по C, пожалуйста, обращайтесь к превосходным c faq и c ++ faq.Вот релевантный ответ на ваш вопрос.http://c -faq.com / ptrs / unopprec2.html .Это связано с приоритетом оператора.* ptr ++ эквивалентен * (ptr ++).

Выход вашей первой итерации должен быть 1 1 1 17

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

0 голосов
/ 02 ноября 2010

Вы, вероятно, смотрите только на последнюю часть вывода, потому что, когда я компилирую его, он показывает каждое значение массива и затем 0 с после того, как вы прошли всю часть кода.

ИЧто касается пустых указателей:

Их также называют универсальными указателями, потому что вы можете назначить их любому типу данных.

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