Размер строки символов - PullRequest
3 голосов
/ 11 февраля 2020

Из кода ниже

#include<stdio.h>
int main()
{
    char *s;
    s="cool man army";  //here LHS and RHS are same type
    printf("ptr= %zd, normal string= %zd",sizeof(s),sizeof("cool man army"));
    return 0;
}

s имеет тип char * и "cool man army" также char *, тогда почему выходы ptr= 8, normal string= 14 отличаются?

Ответы [ 4 ]

7 голосов
/ 11 февраля 2020

Строковый литерал на самом деле является массивом, а не указателем. Раздел 6.4.5p6 C стандарта , касающийся состояний строковых литералов:

На этапе 7 преобразования байт или код нулевого значения добавляются к каждой многобайтовой последовательности символов, которая результат из строкового литерала или литералов. Последовательность многобайтовых символов затем используется для инициализации массива хранения и продолжительности хранения stati c, достаточного только для того, чтобы содержать последовательность.

Поэтому, когда это операнд оператора sizeof, обычное затухание указателя не происходит, и вы возвращаете размер массива в байтах.

Поведение затухания массива в указатель задокументировано в разделе 6.3.2.1p3:

За исключением случаев, когда это операнд оператора sizeof, оператор _Alignof или унарный оператор & или строковый литерал, используемый для инициализации массива, выражение, которое имеет Тип '' массив типа '' преобразуется в выражение с типом '' указатель на тип '', которое указывает на начальный элемент объекта массива и не является lvalue. Если объект массива имеет класс хранения регистров, поведение не определено.

0 голосов
/ 11 февраля 2020

Поскольку вы пометили вопрос как "C", так и "C ++", я отвечу на вопрос для обоих языков.

Предложение

s = "cool man army";

, где s имеет тип char *, допустимо только в C, но не в C ++. В C ++ переменная s должна иметь тип const char *, поскольку строковый литерал распадается до этого типа. Только в C строковый литерал затухает до типа char *. Однако в обоих языках строковый литерал доступен только для чтения, даже если он не const в C.

На современных 64-битных платформах указатели обычно являются 64-битными, поэтому sizeof(s) составляет 8 байтов (что эквивалентно 64 битам). Строковый литерал "cool man army", тем не менее, является массивом, а не указателем (и также не уменьшается до единицы при использовании с оператором sizeof). Следовательно, sizeof("cool man army") - это фактическая длина массива (включая завершающий нулевой символ), которая равна 14.

РЕДАКТИРОВАТЬ: Между тем тег C ++ был удален из вопроса. Однако, поскольку это сделал не ОП, я не буду удалять свои комментарии о C ++ из своего ответа.

0 голосов
/ 11 февраля 2020

Во-первых, ваш код не компилируется в C ++. Вы не можете сбросить const таким образом при сборке в режиме c ++.

Я думаю, что ошибка здесь:

s="cool man army";  //here LHS and RHS are same type

Они не одного типа. Строковые литералы являются символьным массивом, и они распадаются на указатели.

Тип строкового литерала - char const[14]. В C ++ вы можете создать ссылку на него:

auto const& ref_to_literal = "cool man army";
assert(sizeof(ref_to_literal) == sizeof("cool man army")); // True!
0 голосов
/ 11 февраля 2020

Первый - указатель на символ, второй - нет. Вы можете увидеть это с заголовком typeinfo :

printf("%s %s", typeid(s).name(), typeid("cool man army").name());

и увидеть что-то подобное

Pc
A14_c

Вы можете видеть, что второй - это массив из 14 символов.

...