strlen возвращает неправильное значение для 2d-массива

Почему это:

char animals[][30] = {{"cow "}, {"dog "}, {"frog "}, {"gecko "}, {"cat"}};

возвращая 4 вместо 5, когда я делаю это:

printf("%d\n", strlen(animals));

Из того, что я считаю, существует 5 разных массивов массивов символов, поэтому я не уверен, почему он говорит, что их 4.


person Madison Bularia    schedule 11.12.2020    source источник
comment
animals НЕ является строкой   -  person Mark Benningfield    schedule 11.12.2020
comment
Вы должны получить предупреждение о несоответствии типа между animals и аргументом strlen()   -  person Barmar    schedule 11.12.2020
comment
strlen — это сокращение от длины строки. Почему вы ожидаете, что это вернет количество элементов в массиве?   -  person Barmar    schedule 11.12.2020


Ответы (4)


Эта декларация

char animals[][30] = {{"cow "}, {"dog "}, {"frog "}, {"gecko "}, {"cat"}};

не объявляет одномерный массив, содержащий строку.

Тип аргумента функции strlen должен быть char *. Но вы используете аргумент типа char ( * )[30].

Вам нужно следующее

printf( "%zu\n", sizeof( animals ) / sizeof( *animals ) );

Я не уверен, почему он говорит, что их 4.

Потому что в этом вызове printf используется недопустимый спецификатор преобразования %d вместо %zu.

printf("%d\n", strlen(animals));

значение аргумента animals в вызове

strlen(animals)

считается адресом первого элемента массива, длина которого действительно равна 4.

То есть с точки зрения равенства адресов этот вызов

strlen(animals)

эквивалентно вызову

strlen(animals[0])

потому что значение animals, используемое в первом вызове, равно значению адреса его первого элемента animals[0]. Хотя в первом вызове strlen аргумент имеет недопустимый тип.

Компилятор должен выдать сообщение о том, что вы используете неправильный аргумент при вызове strlen.

person Vlad from Moscow    schedule 11.12.2020
comment
На самом деле это эквивалентно strlen(&animals[0]). - person Barmar; 11.12.2020
comment
@Barmar Это то же самое, что и животные [0]. Все эти выражения имеют одинаковое значение. - person Vlad from Moscow; 11.12.2020
comment
@Barmar Требуется для всех архитектур. Адрес массива равен адресу его первого элемента. - person Vlad from Moscow; 11.12.2020
comment
@VladfromMoscow Но, похоже, этому противоречит 6.2.5 Типы, стр. 28: ... Указатели на другие типы не обязательно должны иметь такие же требования к представлению или выравниванию. Принятый ответ на в этом вопросе даже говорится, что нет явного требования, чтобы адрес массива был равен адресу его первого элемента. Похоже на хороший вопрос языкового юриста. - person Andrew Henle; 11.12.2020
comment
@AndrewHenle Тип элемента массива не является другим типом. Адрес многомерного массива — это адрес его первого элемента и адрес первого элемента этого первого элемента. Все три значения равны друг другу и являются адресом экстента, выделенного для массива. - person Vlad from Moscow; 11.12.2020

strlen() предназначен для вычисления длины строк (последовательность символов в C, заканчивающаяся нулем) , а не для вычисления количества элементов массива.

Чтобы получить количество элементов в массиве, вы можете разделить размер массива на размер элемента массива.

printf("%zu\n", sizeof(animals) / sizeof(*animals));

Также обратите внимание, что вы должны использовать %zu, а не %d, чтобы напечатать size_t (strlen() и sizeof возвращают size_t)

person MikeCAT    schedule 11.12.2020

Есть несколько проблем с вызовом printf("%d\n", strlen(animals));

  • формат printf должен быть %zu, если strlen был правильно объявлен путем включения <string.h> в момент вызова. Это вряд ли создаст проблему, но должно быть исправлено.
  • strlen() принимает строку C, а animal не является строкой C, это двумерный массив char. Вместо этого вы должны пройти strlen(animal[0]). Опять же, эта ошибка вряд ли создаст проблему, потому что адрес первой строки в 2D-массиве совпадает с адресом самого массива. Чтобы вычислить количество элементов в 2D-массиве, используйте sizeof(animal) / sizeof(*animal).
  • вызов должен напечатать 4 (строка "cow " имеет завершающий пробел) и новую строку, а возвращаемое значение будет 2 как количество символов, выводимых printf.

Попробуйте эту модифицированную версию:

#include <stdio.h>
#include <string.h>

int main() {
    char animals[][30] = {{"cow "}, {"dog "}, {"frog "}, {"gecko "}, {"cat"}};

    printf("number of strings: %zu\n", sizeof(animals) / sizeof(*animals));
    for (size_t i = 0; i < sizeof(animals) / sizeof(*animals); i++) {
        printf("%zu: \"%s\", %zu chars\n", i, animals[i], strlen(animals[i]));
    }
    return 0;
}
person chqrlie    schedule 11.12.2020

Основной ответ на ваш вопрос

возвращая 4 вместо 5, когда я делаю это

когда ты это сделаешь

printf("%d\n", strlen(animals));

animals — это указатель на первую из строк, животные хранятся в памяти как cow \0........dog \0... где ..... — байты до следующего элемента массива (обычно случайного материал памяти, если он не инициализирован). Когда вы печатаете strlen животных, он возвращает strlen коровы.

Вы смешиваете типы.. c позволяет это, потому что на самом деле они являются указателями, поэтому компилятор работает, но это неправильно.

чтобы получить 5 в результате, вам нужно будет сделать это

printf("%zu",sizeof(animals) /sizeof(animals[0]));
person hamboy75    schedule 11.12.2020