Я приехал для беспокойства Вас всех другим, вероятно, действительно простой вопрос C.
Использование следующего кода:
int get_len(char *string){
printf("len: %lu\n", strlen(string));
return 0;
}
int main(){
char *x = "test";
char y[4] = {'t','e','s','t'};
get_len(x); // len: 4
get_len(y); // len: 6
return 0;
}
2 вопроса. Почему они отличаются и почему y 6?Спасибо, ребята.
Править: Извините, я знаю то, что зафиксировало бы его, я отчасти просто хотел понять то, что продолжалось. strlen просто продолжает передавать точку, пока это, оказывается, не находит \0? Также, когда я сделал strlen в основной функции вместо в функции get_len, оба равнялись 4. Это было просто совпадением?
y
не заканчивается нулем. strlen ()
считает символы, пока не встретит нулевой символ. Вашему довелось найти один после 6, но это могло быть любое число. Попробуйте следующее:
char y [] = {'t', 'e', 's', 't', '\ 0'};
Вот что такое реализация strlen ()
может выглядеть так (в верхней части моей головы - у меня нет под рукой моей книги K&R, но я считаю, что там есть реализация):
size_t strlen(const char* s)
{
size_t result = 0;
while (*s++) ++result;
return result;
}
Вам нужно завершить y нулевым символом в конце.
int get_len(char *string){
printf("len: %lu\n", strlen(string));
return 0;
}
int main(){
char *x = "test";
char y[5] = {'t','e','s','t','\0'};
get_len(x); // len: 4
get_len(y); // len: 4
return 0;
}
strlen () в основном берет указатель, который вы ему даете, и подсчитывает количество байтов до следующего NULL в памяти. Так уж получилось, что двумя байтами позже в вашей памяти был NULL.
Фактическая строка C-типа на единицу больше, чем количество ее символов, поскольку ей нужен завершающий нулевой символ.
Следовательно, char y [4] = {'t', 'e', 's', 't'};
не формирует строку, так как это четыре символа. char y [] = "test";
или char y [5] = "test";
будут формировать строку, поскольку они будут иметь массив символов из пяти символов, оканчивающихся на терминатор нулевого байта.
Как уже говорили другие, вам просто нужно обязательно закончить строку символом 0 или '\ 0'. В качестве примечания вы можете проверить это: http://bstring.sourceforge.net/ . Он имеет функцию длины строки O (1), в отличие от strlen C / C ++, которая подвержена ошибкам и медленна при O (N), где N - количество ненулевых символов. Я не помню, когда в последний раз использовал strlen и его друзья. Выбирайте безопасные и быстрые функции / классы!
Следующее не является массивом символов с завершающим нулем:
char y[4] = {'t','e','s','t'};
Часть контракта strlen ()
заключается в том, что ему должен быть предоставлен указатель на строку с завершающим нулем. Поскольку этого не происходит с strlen (y)
, вы получаете неопределенное поведение. В вашем конкретном случае вы получите 6
, но может произойти что угодно, включая сбой программы.
Из раздела 7.1.1 C99 «Определение терминов»:
строка - это непрерывная последовательность символов, оканчивающаяся первым нулевым символом и включающая его.
strlen
работает с строками . Строка определяется как последовательность (массив) символов, оканчивающихся символом \ 0
.
Ваш x
указывает на строку. Итак, strlen
отлично работает с x
в качестве аргумента.
Ваш y
не является строкой. По этой причине передача y
в strlen
приводит к неопределенному поведению. Результат бессмысленный и непредсказуемый.
char y[5] = {'t','e','s','t','\0'};
будет таким же, как
char *x = "test";
Это
char y[4] = {'t','e','s','t'};
не является правильной строкой с завершающим нулем . Это массив из четырех символов, без завершающего '\ 0'
. strlen ()
просто считает символы, пока не достигнет нуля. С y
он просто считает до конца массива, пока случайно не найдет нулевой байт.
При этом вы вызываете неопределенное поведение. Код может с таким же успехом отформатировать ваш жесткий диск.
Этого можно избежать, используя специальный синтаксис для инициализации массива символов:
char y[] = "test";
Это инициализирует y
с пятью символами, поскольку автоматически добавляет '\ 0 '
.
Обратите внимание, что я также не указал размер массива. Компилятор сам это вычисляет и автоматически повторно вычисляет, если я изменяю длину строки.
Кстати, вот простая реализация strlen ()
:
size_t strlen(const char* p)
{
size_t result = 0;
while(*p++) ++result;
return result;
}
Современные реализации, скорее всего, не будут извлекать отдельные байты или даже использовать встроенные функции ЦП, но это основной алгоритм.