Подтвердить что ты не робот

Почему указатель + 1 добавляет 4 на самом деле

#include<stdio.h>
int main(void){
  int *ptr,a,b;
  a = ptr;
  b = ptr + 1;
  printf("the vale of a,b is %x and %x respectively",a,b);

  int c,d;
  c = 0xff;
  d = c + 1;
  printf("the value of c d are %x and %x respectively",c,d);
  return 0;
}

значение out put

the vale of a,b is 57550c90 and 57550c94 respectively
the value of c d are ff and 100 respectively%  

на самом деле получается ptr + 1, почему он так себя ведет?

4b9b3361

Ответ 1

Подумайте, что такое указатель... это адрес памяти. Каждый байт в памяти имеет адрес. Итак, если у вас есть int что 4 байта и его адрес 1000, 1001 фактически является вторым байтом этого int а 1002 - третьим байтом, а 1003 - четвертым. Поскольку размер int может отличаться от компилятора к компилятору, крайне важно, чтобы при инкрементах указателя вы не получали адрес некоторой средней точки в int. Таким образом, задача определения количества пропущенных байтов на основе вашего типа данных обрабатывается для вас, и вы можете просто использовать любое значение, которое вы получаете, и не беспокоиться об этом.

Как указывает Базиле Старинквич, эта сумма будет варьироваться в зависимости от свойства sizeof указанного элемента данных. Очень легко забыть, что даже если адреса последовательны, указатели на ваши объекты должны учитывать фактическое пространство памяти, необходимое для размещения этих объектов.

Ответ 2

Поскольку указатели предназначены для совместимости с массивами:

*(pointer + offset)

эквивалентно

pointer[offset]

Таким образом, арифметика указателя не работает в байтах, а в единицах размера sizeof(pointer base type) -bytes.

Ответ 3

Вам действительно нужно потратить время, чтобы прочитать хорошую C-языков программирования языка программирования (например, K & R "язык программирования C")

Арифметика указателя - сложный вопрос. Добавление указателя означает переход к следующему остроконечному элементу. Таким образом, адрес увеличивается по sizeof заостренного элемента.

Ответ 4

Короткий ответ

Адрес указателя будет увеличен на sizeof(T) где T - указанный тип. Таким образом, для int указатель будет увеличиваться на sizeof(int).

Зачем?

Ну, в первую очередь, стандарт требует этого. Причина, по которой это поведение полезна (кроме совместимости с C), заключается в том, что когда у вас есть структура данных, которая использует непрерывную память, например массив или std::vector, вы можете перейти к следующему элементу массива, просто добавив один к указателю. Если вы хотите перейти к n-му элементу в контейнере, вы просто добавите n.

Возможность записи firstAddress + 2 намного проще, чем firstAddress + (sizeof(T) * 2) и помогает предотвратить ошибки, возникающие у разработчиков, если sizeof(int) равен 4 (это может быть не так) и писать код, например firstAddress + (4 * 2).

Фактически, когда вы говорите myArray[4], вы говорите myArray + 4. Это причина, по которой индексы массивов начинаются с 0; вы просто добавляете 0, чтобы получить первый элемент (т.е. myArray указывает на первый элемент массива) и n, чтобы получить n-й.

Что делать, если я хочу переместить один байт за раз?

sizeof(char) гарантированно будет иметь один байт, поэтому вы можете использовать char* если вы действительно хотите переместить один байт за раз.

Ответ 5

Указатель используется для указания на конкретный байт метки памяти, где был выделен объект (технически он может указывать в любом месте, но как он используется). Когда вы выполняете арифметику указателей, она работает в зависимости от размера объектов, на которые указывает. В вашем случае это указатель на целые числа, размер которых по 4 байта.

Ответ 6

Пусть рассмотрим указатель p. Выражение p+n равно (unsigned char *)p + n * sizeof *p (потому что sizeof(unsigned char) == 1). Попробуй это:

#include <stdio.h>
#define N   3

int
main(void)
{
    int i;
    int *p = &i;
    printf("%p\n", (void *)p);
    printf("%p\n", (void *)(p + N));
    printf("%p\n", (void *)((unsigned char *)p + N * sizeof *p));
    return 0;
}