В чем смысл типов указателей в C++?
Вопрос
Допустим, у меня есть несколько указателей:
char * pChar;
int * pInt;
Я знаю, что они оба просто содержат адреса памяти, указывающие на какое-то другое место, и что типы определяют, насколько велика ячейка памяти, на которую указывает конкретный указатель.Так, например, char может иметь размер байта в системе, а int может иметь размер 4 байта.Итак, когда я это делаю:
pChar++; // I am actually incrementing the address pointed to by pChar by 1 byte;
pInt++; // I am actually incrementing the address pointed to by pInt by 4 bytes;
Но что, если я сделаю это:
pChar+2; // increment the address pointed to by pChar by 2 bytes?
pInt+2; // increment the address pointed to by pInt by 2 bytes? what happens to the other two bytes?
Спасибо..Буду признателен за любые разъяснения здесь.Является ли тип указателя просто для операции ++?
РЕДАКТИРОВАТЬ:Итак, avp правильно ответил на мой вопрос, но у меня есть дополнительный вопрос: что произойдет, когда я это сделаю:
memcpy(pChar,pInt,2);
Будет ли он копировать 2 байта?или 4 байта?Будет ли у меня нарушение доступа?
РЕДАКТИРОВАТЬ:Ответ, по мнению Райана Фокса, — 2 байта, потому что они приводятся к типу (void*).Спасибо!ЗАКРЫТО!
РЕДАКТИРОВАТЬ:Просто чтобы будущие искатели могли это найти..Еще одна информация, которую я обнаружил..
memcpy(pChar+5,pInt+5,2);
не копирует 2 байта блока памяти, на который указывает pInt+5bytelocations, в pChar+5bytelocations..происходит следующее: 2 байта копируются в pChar+5bytelocations из pInt(4*5)bytelocations..неудивительно, что у меня были нарушения прав доступа, я пытался прочитать то, что не должен был читать..:)
Решение
«++» — это просто другое имя для X = X + 1;
Для указателей не имеет значения, увеличиваете ли вы их на 1 или на N.В любом случае используется sizeof(type)*N.В случае 1 это будет просто sizeof(type).
Итак, когда вы увеличиваете на 2 (ваш второй случай):
для char — 2*sizeof(char)=2*1=2 байта,
для int будет 2*sizeof(int)=2*4=8 байт.
Другие советы
Ааа, теперь я понимаю.Ты должен был спросить - «Какой смысл иметь типы указателей?»
На самом деле есть два момента:
- Указательная арифметика;
- Разыменование (возвращение значения, хранящегося по адресу, на который указывает указатель).
И то, и другое было бы невозможно без знания типа указателя.
Добавлен: Прочтите документацию memcpy.Последний аргумент — количество байтов, поскольку memcpy понятия не имеет, какой тип указателя.Оба аргумента являются пустыми указателями.
Добавлено 2: Нарушение прав доступа - это зависит.Если вы не выходите за пределы памяти, выделенной для этих указателей, нарушения прав доступа не будет.Операция копирования скопирует все побайтно, и вы получите результаты именно так, как ожидаете (хотя это может не иметь особого смысла).
Если вы выходите за пределы выделенной памяти, то вы мощь получите нарушение прав доступа, но с таким же успехом вы можете просто перейти в память, выделенную для другой переменной.Практически невозможно предсказать, что и где происходит при выполнении вашей программы, поэтому это приведет к совершенно непредсказуемым результатам.
У указателей есть три основных преимущества:
- Вы можете передавать аргументы функции «по ссылке».Раньше это было большей проблемой в C, где не было реальных ссылок, таких как C++, но во многих случаях это по-прежнему очень полезно, например, когда вам приходится сотрудничать с внешними библиотеками.Также обратите внимание, что передача по ссылке полезна не только тогда, когда вы хотите, чтобы функция изменила передаваемую вами переменную.Это также очень удобно для передачи больших структур данных в качестве параметров.
- Для создания всевозможных изящных динамических структур данных, таких как деревья, связанные списки и т. д.Без указателей это было бы невозможно.
- За возможность перераспределять массивы на большие/меньшие по мере необходимости.
P.S.Я понимаю, что вопрос был о том, чем хороши указатели, на примере арифметики, верно?
Арифметика указателей работает не совсем так.Ваш первый пример верен, второй не очень.
pChar+2; // increment the address pointed to by pChar by 2 bytes
pInt+2; // increment the address pointed to by pInt by 8 bytes
Для этой части:
memcpy(pChar+5,pInt+5,2);
Сначала оценивается «+», затем приведение типа.
Итак, в байтах:
pChar+5 здесь «5» — это 5 байт,
pInt+5 здесь «5» — это 5 целых чисел, поэтому 5 * 4 = 20 байт.
Затем все преобразуется в void* и копируются два байта.
Если вместо «5» вы используете счетчик, как здесь:
for (int i = 0; i<100; i++)
memcpy(pChar+i, pInt+i, 2);
Затем для pChar вы перезапишете один скопированный байт (второй) следующей командой копирования.А для pInt вы будете прыгать на 4 байта на каждом шаге (хотя для массива целых чисел это нормально).
Я бы сказал, что смысл типов указателей в С++ заключается в учете смещений vtable.