Я читал следующий текст из класса Парадигм программирования Стэнфорда, и я заметил, что, когда автор использует строковый класс, конструктор делает вызов функции, который похож на это:
string::string(const char* str) {
initializeFrom(str, str + strlen(str));
}
Если initializeFrom функция берет два символа* аргументы, каким образом второй аргумент может передать (символ* + интервал) к символу* и иметь его, удаются правильно? Как система типов интерпретирует этот оператор?
Заранее спасибо.
Это называется арифметикой указателей. char* + int приводит к char*, который находится на int символов выше в памяти.
Я думаю, что это может быть уже отвечено.
В:
initializeFrom(str, str + strlen(str));
str
- это указатель на начало строки.
(str + strlen(str))
- указатель на конец строки.
Следует помнить, что str
(символьный указатель) - это просто целое число ((int)
, (long)
, (long long)
в зависимости от архитектуры), которое идентифицирует место в памяти.
Бинарные аддитивные операторы +
и -
можно использовать, когда один аргумент является указателем на любой полный тип (скажем, T* p
), а другой аргумент - целое число (скажем, i
). Они реализуют так называемую стрелочную арифметику.
Компилятор предполагает, что указатель указывает на элемент некоторого массива (скажем, T array[N]
). В результате операции получается указатель на другой элемент массива, который находится на расстоянии i
элементов от исходного элемента. Указатель можно "двигать" в любом направлении, то есть к началу массива или к его концу. Например, если p
указывает на массив[3]
, то p + 4
будет указывать на массив[7]
.
Операция действительна только тогда, когда результат указывает на существующий элемент массива или на элемент, прошедший последний элемент массива, т.е., учитывая массив T array[N]
, можно создавать указатели на элементы от array[0]
до мнимого элемента array[N]
. Любые попытки пересечь эти границы с помощью арифметики указателей приводят к неопределенному поведению.
Тип T
должен быть полным, что означает, что арифметика указателей не может использоваться с указателями void *
, например, хотя некоторые компиляторы позволяют это в качестве расширения (рассматривая указатели void *
как эквивалентные указателям char *
).
В дополнение к двоичным аддитивным операторам, арифметика указателей также включает префиксные и постфиксные унарные операторы ++
и --
(применяются к указателям), а также составные операторы присваивания +=
и -=
(с указателями в левой части и целыми числами в правой части).
В вашем случае выражение str + strlen(str)
создаст указатель типа char *
, который указывает на конечный \0
символ в строке str
.
Первый аргумент указывает на начало массива char, а второй указывает на NULL char в конце массива char.
const char *str = "abc";
char *start = str; // start now points to the first char.
char *end = str + strlen(str); // end now points to the null char at the end.
Вы можете подтвердить это, напечатав:
printf("%c %d",*start,*end); // will output: a 0
почему второй аргумент может передавать (char * + int)
Он все еще передает char *
, указывающий на strlen (str)
за первоначально указанным местоположением.
Помните, что указатель - это просто переменная, содержащая адрес памяти. Таким образом, вы можете добавлять значения в адрес памяти. Адрес памяти - это число.
Когда вы добавляете 1 к указателю определенного типа, фактически добавляется 1 * sizeof (type). Когда вы добавляете любое значение N, оно фактически добавляет N * sizeof (type).
Рассмотрим следующий пример:
int x[5] = {0,1,2,3,4};
int *p = &(x[0]);//point to the first element
p = p + 1;//p now points to the second element.