Почему указатель + 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, почему он так себя ведет?
Ответы
Ответ 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;
}