Указатели на символы и целочисленные указатели (++) - PullRequest
4 голосов
/ 09 апреля 2010

У меня есть два указателя,

char *str1;
int *str2;

Если я посмотрим на размер обоих указателей, давайте предположим

str1=4 bytes
str2=4 bytes

str1 ++ будет увеличиваться на 1 байт, но если str2 ++, он будет увеличиваться на 4 байта.

Какая концепция стоит за этим?

Ответы [ 10 ]

16 голосов
/ 09 апреля 2010

Простой, в предоставленном сценарии:

  • длина символа - 1 байт
  • int (в вашей платформе) имеет длину 4 байта

Оператор ++ увеличивает указатель на размер указанного типа.

9 голосов
/ 09 апреля 2010

При выполнении арифметики с указателем, это всегда в терминах объектов, на которые указывают, а не в байтах.

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

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

4 голосов
/ 09 апреля 2010

A char - 1 байт, int - (обычно) 4 байта. Когда вы увеличиваете указатель, вы увеличиваете размер данных, на которые указывают. Так, когда вы увеличиваете char*, вы увеличиваете на 1 байт, но когда вы увеличиваете int*, вы увеличиваете 4 байта.

3 голосов
/ 09 апреля 2010

Указатель фактически содержит адрес ячейки памяти, который составляет 4 байта целое число. str1 указывает на местоположение, которое содержит 1 байт, поэтому, если вы увеличите адрес str1, он перейдет к следующему адресу 1-байтовых данных. Но в другом случае str2 указывает на 4-байтовые данные, поэтому, если вы увеличите этот адрес, он должен перепрыгнуть через эти данные, чтобы перейти к следующим 4-байтовым данным, поэтому он увеличивается на 4.

Вот как 1-байтовая последовательность данных сохраняется в памяти:

ADDRESS:         FF334400  FF334401  FF334402  FF334403
DATA (1BYTE):           1         2         3         4

Так что, если str1 хочет указать на число 2, он должен сохранить свой адрес, который является FF334401. Если вы увеличиваете str1, он должен перепрыгнуть через адрес 2s и получить значение 3, а для этого его нужно увеличить на 1.

В другом случае:

ADDRESS:         FF334400  FF334401  FF334402  FF334403 FF334404 ... FF334407
DATA (4BYTE):           0         0         0         1        0            2

Теперь, если str2 указывает на число 1, которое является целым числом, и оно на самом деле является 4-байтовыми данными, оно указывает на начало этих данных, которые являются адресом FF334400. Когда вы увеличиваете его, он должен перепрыгнуть через все 4 байта данных 1s, чтобы получить данные 2s, поэтому он увеличивается на 4, и его адрес становится FF334404, который является первым байтом 4-байтовых данных числа 2.

1 голос
/ 09 апреля 2010

Подсказка: p[i] является сокращением для *(p + i).

0 голосов
/ 09 апреля 2010

Указатель - это абстракция, которая позволяет ссылаться на данные в памяти так, чтобы к необработанной памяти обращались как к элементарной единице, чтобы гарантировать ее правильную интерпретацию для выбранного типа.

Сам указатель представлен собственным машинным размером слова. В вашем примере у вас есть два указателя на разные типы, но они по-прежнему являются указателями на адреса в памяти, и поэтому они имеют одинаковый размер. Как упоминалось в других ответах, для получения размера типа данных, на который указывает указатель, необходимо разыменовать его в операции sizeof, например SizeOf (* р).

Оператор ++ позволяет получить указатель, который ссылается на следующий адрес в памяти для соответствующего типа. Если он просто увеличивает адрес на один байт для всех типов, вы можете получить адрес в памяти, который указывает на середину представления данных

например. для двух 4-байтовых целых чисел без знака, представляющих десятичные значения 1 и 4 278 190 080 соответственно, начиная с адреса 0x00 в памяти (обратите внимание, что этот адрес приведен только для иллюстрации и не представляет реальную систему, поскольку ОС зарезервирует их для своих собственных целей) 1007 *

address                          0x00  0x01  0x02  0x03  |  0x04 0x05 0x06 0x07
data value (4 byte integer)      0x00  0x00  0x00  0x01  |  0xFF 0x00 0x00 0x00

Если указатель на целое число имеет ссылку на адрес 0x00, а оператор ++ просто увеличил адрес указателя на 1 байт, у вас будет указатель на адрес 0x01, который, если вы затем получите доступ к этому адресу (плюс последующие 3 байта) как целое число, вы получите целое число, которое представлено байтами данных 0x00 0x00 0x01 плюс значение адреса 0x04, которое в этом случае является значением 0xFF. Это привело бы к целому числу с десятичным значением 511, которое не представляет ни одно из 2 целых чисел, хранящихся в памяти.

Чтобы правильно получить доступ к следующему целому числу в памяти, оператор ++ должен увеличить байтовый адрес указателя на 4 байта.

0 голосов
/ 09 апреля 2010

Это в соответствии с арифметикой указателя. Вот и все ..

Как вы сказали, память, выделенная для всех указателей, одинакова. Но когда вы используете оператор приращения с переменной указателя, это означает, что указатель должен быть сделан, чтобы указывать (увеличивать) на следующее место в памяти.

Итак, если вы используете символьный указатель, то при увеличении вы хотите указать следующий символ шириной в один байт. Точно так же, если вы хотите увеличить целочисленный указатель, то это все равно, что попросить его указать следующее целое число шириной четыре байта.

Думаю, этого будет достаточно, чтобы прояснить ваш вопрос:)

0 голосов
/ 09 апреля 2010

Simple. Это зависит от компилятора.

Если int имеет 4 байта размера, когда вы добавляете 1 к его указателю, он добавляет к нему свой размер, то есть, а если int имеет 2 байта, то он добавляет к указателю 2, равный размеру. Например, в Turbo C ++

int *str = NULL;
str + 1;    //It will add 2 as Turbo C++ has int size 2 bytes

In Visual C ++ , str + 1; // Это добавит 4, поскольку Visual C ++ имеет размер int 4 байта.

И то же самое происходит с char.

0 голосов
/ 09 апреля 2010

Приращение указателя всегда увеличивает адрес, на который он указывает, на размер представляемого им типа. Таким образом, для указателя на символ он увеличивается на 1, а для целого на 4. Но самой переменной указателя потребуется 4 байта для хранения адреса.

Вы можете подумать о том, как работает индексирование массивов. Incase целочисленного массива a [0] будет указывать на первый элемент, а a [1] будет указывать на второй. В этом случае с шагом 1 он должен увеличиваться на 4 байта для доступа к следующему целому числу. В случае символов это должно быть 1. То же самое понятие работает для всей арифметики указателя.

0 голосов
/ 09 апреля 2010

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

Рассмотрим массив и целочисленный указатель на этот массив:

int p[10];
int *q = p;

Тогда * (q + 1) совпадает с p [1], то есть следующим int в памяти. Было бы гораздо менее полезно, если бы он просто указывал на один байт вперед.

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