Как найти длину строки: strlen и sizeof
Длину строки — число символов до '\0' — возвращает функция strlen из string.h:
#include <stdio.h>
#include <string.h>
int main(void) {
char buf[100] = "hello";
char word[] = "hello";
char *p = "hello";
printf("strlen: %zu %zu %zu\n", strlen(buf), strlen(word), strlen(p));
printf("sizeof: %zu %zu %zu\n", sizeof(buf), sizeof(word), sizeof(p));
return 0;
}strlen: 5 5 5
sizeof: 100 6 8strlen для всех трёх строк одинаков — 5. А sizeof измеряет совсем другое:
sizeof(buf)— размер массива, сколько бы символов в нём ни было: 100;sizeof(word)— массив, размер которого компилятор посчитал по строке: 5 букв и'\0', всего 6;sizeof(p)— размер указателя, а не строки: 8 байт в 64-битной программе (4 — в 32-битной).
Результат обоих — тип size_t, его выводят форматом %zu. С %d gcc предупреждает: format '%d' expects argument of type 'int', but argument 2 has type 'size_t'.
sizeof в функции
Массив, переданный в функцию, превращается в указатель. Поэтому внутри функции sizeof у параметра — всегда 8, а длину строки там узнают только через strlen:
#include <stdio.h>
#include <string.h>
void info(const char *s) {
printf("Длина: %zu\n", strlen(s));
}
int main(void) {
info("abc");
info("");
return 0;
}Длина: 3
Длина: 0Если написать параметр как char s[], ничего не изменится — это тот же указатель, и gcc об этом предупреждает: 'sizeof' on array function parameter 's' will return size of 'char *'.
Подводные камни
Перевод строки после fgets. fgets оставляет в строке \n, и strlen его считает: для введённого hello получится 6. Уберите его до подсчёта: s[strcspn(s, "\n")] = '\0';.
Русские буквы. В UTF-8 русская буква занимает два байта, а strlen считает байты: strlen("кот") равно
- Число символов для такого текста приходится считать самому: в UTF-8 у каждого символа ровно один байт, который
не начинается с битов 10.
#include <stdio.h>
int main(void) {
char s[] = "кот и dog";
int chars = 0;
for (int i = 0; s[i] != '\0'; i++) {
if (((unsigned char)s[i] & 0xC0) != 0x80) {
chars++;
}
}
printf("Символов: %d\n", chars);
return 0;
}Символов: 9strlen в условии цикла. for (i = 0; i < strlen(s); i++) вызывает strlen на каждом шаге, а он каждый раз пробегает всю строку. Для длинных строк это медленно — посчитайте длину один раз до цикла: size_t n = strlen(s);.
strlen без '\0'. strlen идёт по памяти, пока не встретит ноль. Если массив заполнен символами без завершающего '\0', результат не определён: strlen выйдет за границы массива.