Глиф Учебники

Как найти длину строки: strlen и sizeof

Справочник · C · 2 минуты чтения

Длину строки — число символов до '\0' — возвращает функция strlen из string.h:

C
#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 8

strlen для всех трёх строк одинаков — 5. А sizeof измеряет совсем другое:

Результат обоих — тип size_t, его выводят форматом %zu. С %d gcc предупреждает: format '%d' expects argument of type 'int', but argument 2 has type 'size_t'.

sizeof в функции

Массив, переданный в функцию, превращается в указатель. Поэтому внутри функции sizeof у параметра — всегда 8, а длину строки там узнают только через strlen:

C
#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("кот") равно

  1. Число символов для такого текста приходится считать самому: в UTF-8 у каждого символа ровно один байт, который

не начинается с битов 10.

C
#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;
}
Вывод
Символов: 9

strlen в условии цикла. for (i = 0; i < strlen(s); i++) вызывает strlen на каждом шаге, а он каждый раз пробегает всю строку. Для длинных строк это медленно — посчитайте длину один раз до цикла: size_t n = strlen(s);.

strlen без '\0'. strlen идёт по памяти, пока не встретит ноль. Если массив заполнен символами без завершающего '\0', результат не определён: strlen выйдет за границы массива.