Я попытался вычислить длину массива символов следующими способами:
char *s="abcde";
int n=sizeof(s)/sizeof(s[0]);
cout<<n;
n выводится как постоянное значение 4, независимо от того, как долго длится строка. Принимая во внимание, что я объявил массив как
char s[]="abc";
int n=sizeof(s)/sizeof(s[0]);
cout<<n;
Выход по-прежнему остается 4. Я понимаю, что во втором случае он включает заключительный символ '\ 0', следовательно, вывод. Единственное, что я не понял, - это то, почему я получаю постоянный вывод в первом случае.
В этом фрагменте кода
char *s="abcde";
int n=sizeof(s)/sizeof(s[0]);
cout<<n;
s - указатель. Поэтому sizeof (s) равен размеру указателей в системе. В вашей системе размер указателя равен 4. Поскольку тип s [0] является char, тогда его размер равен 1, и вы получите значение 4.
Во втором фрагменте кода
char s[]="abc";
int n=sizeof(s)/sizeof(s[0]);
cout<<n;
s - массив. Его размер определяется размером инициализатора. Поскольку строковый литерал "abc" имеет размер, равный 4, так как нулевой конец также подсчитывается, тогда размер массива s равен 4. Если вы, например, напишете
char s[]="abcde";
int n=sizeof(s)/sizeof(s[0]);
cout<<n;
то размер строкового литерала равен 6, и соответственно размер массива будет равен 6.
Вы можете переписать один и тот же код следующим образом
char s[6]="abcde";
int n=sizeof(s)/sizeof(s[0]);
cout<<n;
Если вы напишете этот код как
char s[10]="abcde";
int n=sizeof(s)/sizeof(s[0]);
cout<<n;
то размер массива будет равен 10, хотя размер строкового литерала равен 6. Все остальные элементы массива, которые не имеют инициализатора, будут инициализированы нулем. Это будет выглядеть так:
[a][b][c][d][e]['\0']['\0']['\0']['\0']['\0']
char *s
является указателем на символ или последовательность символов char. В 32-битной архитектуре она будет иметь ширину 4 байта, поэтому sizeof(s)
будет 4. Один символ (обычно) 1 байт, поэтому sizeof(s[0])
будет 1. Следовательно, n
будет равно 0.
Когда вы используете тип char[]
компилятор рассматривает его как последовательность фиксированной длины, он просто определяет, как долго последовательность будет для вас, в вашем случае это 4 символа. Однако, если бы у вас было:
char s[]="Hello, world";
int n=sizeof(s)/sizeof(s[0]);
Тогда n
будет 13, так как там введен 12 символов, плюс нулевой ограничитель в конце.
char*
.
С char *s
вы создаете указатель s
, указывающий на другую память. С char s[] =...
вы создаете массив из N символов.
Может быть, это проще, если вы посмотрите на это следующим образом:
Для версии указателя char *s = "abcde"
это будет что-то вроде
+---+ +-----------+ | s | ---> | "abcde\n" | +---+ +-----------+
Хотя для случая с массивом char s[] = "abc"
это будет похоже на
+---------+ | "abc\0" | +---------+
Это должно помочь вам понять, почему вы не можете использовать sizeof
для указателя, поскольку он возвращает размер указателя, а не то, на что он указывает. Я также добавил ограничитель строк, который существует для всех строковых литералов, и именно поэтому вы получаете размер 4 для массива, на самом деле это четыре символа.
В первом случае s
является объектом типа char*
. sizeof(s)
оценивает размер этого объекта "указатель на символ", который равен 4 (в вашей среде исполнения), а не длина строки, на которую указывает s
(для чего оценивается strlen(s)
).
char *str
иchar str[]
и тем, как они хранятся в памяти