Значение s++
является исходным значением s
, до увеличения, приращение происходит в неуказанное время до следующей точки последовательности.
Следовательно *s++
и *(s++)
эквивалентны: они оба разыменовывают исходное значение s
. Другое эквивалентное выражение, *(0, s++)
и, не для слабонервных, таково это:0[s++]
Обратите внимание, что ваша функция должна использовать тип size_t
for i
и тип возвращаемого значения:
size_t str_len(const char *s) {
size_t i = 0;
while (*s++) {
i++;
}
/* s points after the null terminator */
return i;
}
Вот потенциально более эффективная версия с одним шагом на цикл:
size_t str_len(const char *s) {
const char *s0 = s;
while (*s++) {
/* nothing */
}
return s - 1 - s0;
}
Для тех, кто интересуется странными выражениями во втором абзаце:
0, s++
является экземпляром оператора запятой, ,
который оценивает его левую часть, а затем правую часть, которая составляет его значение. следовательно (0, s++)
эквивалентно (s++)
.
0[s++]
эквивалентно (s++)[0]
и *(0 + s++)
или или *(s++ + 0)
которые упрощают как *(s++)
. Транспонирование указателя и индексных выражений в []
выражениях не очень распространено и не особенно полезно, но соответствует стандарту C.
, s++
и плохие вещи случатся:)
В этом примере
s
указывает на'a'
в"a"
. Затем он увеличивается, аi
также увеличивается. Теперьs
укажите на нулевой терминатор иi
есть1
. Таким образом, при следующем запуске цикла*(s++)
будет'\0'
(что есть0
), так что цикл заканчивается, и возвращается текущее значениеi
(это1
).Как правило, цикл запускается один раз для каждого символа в строке, а затем останавливается на нулевом терминаторе, поэтому он подсчитывает символы.
источник
s
хранится до увеличения. То, что вы описываете, это поведение++s
(которое действительно будет недооцениваться на единицу и вызывать UB, если передается пустая строка).Это имеет смысл:
Именно поэтому указатель увеличивается, а не символ, скажем, у вас
(*s)++
, в этом случае будет увеличиваться символ, а не указатель. Разыменование означает, что вы теперь работаете со значением, на которое ссылается указатель, а не с самим указателем.Поскольку оба оператора имеют одинаковый приоритет, но ассоциативность справа налево, вы даже можете использовать просто
*s++
без скобок для увеличения указателя.источник
Оператор постинкрементного увеличения значения операнда на 1, но значение выражения является исходным значением операнда до операции приращения.
Предположим, что аргумент передан
str_len()
is"a"
. Вstr_len()
, указательs
указывает на первый символ строки"a"
. Вwhile
цикле:хотя значение
s
будет увеличиваться, но значениеs
в выражении будет указателем на символ, на который оно указывает перед увеличением, то есть указателем на первый символ'a'
. Когда указательs
разыменовывается, он будет давать символ'a'
. На следующей итерацииs
указатель будет указывать на следующий символ, который является нулевым символом\0
. Когдаs
разыменовывается, это даст,0
и цикл будет выход. Обратите внимание, чтоs
теперь будет указывать на один элемент после нулевого символа строки"a"
.источник