Разница между char * и int *
В чем разница между char*
и int*
? Конечно, они имеют разные типы, но как я могу писать
char* s1="hello world";
а
"hello world"
это не один символ, это массив символов, и я не могу написать
*s1
а
char* s1 = {'h','e','l','l','o',' ','w','o','r','l','d'};
и
int* a = {2,3,1,45,6};
В чем разница?
Ответы
Ответ 1
Это довольно просто: строковый литерал, т.е. "foobar"
, скомпилирован в массив символов, который хранится в статическом разделе вашей программы (т.е. где хранятся все константы) и завершается нуль. Затем, присваивая это переменной, просто присваивает переменную переменную указателю на эту память. Например, const char* a = "foo";
назначит адрес, где "foo"
хранится в a
.
Короче говоря, строковая константа уже содержит память, в которой она должна храниться вместе с ней.
Напротив, инициализация указателя с помощью списка инициализаторов (т.е. списка элементов внутри фигурных скобок) не определена для указателей. Неформально проблема с списком инициализаторов - в отличие от строкового литерала - заключается в том, что он не "приносит свою собственную память". Поэтому мы должны предоставить память, в которой список инициализаторов может хранить свои символы. Это делается путем объявления массива вместо указателя. Это прекрасно компилируется:
char s1[11]={'h','e','l','l','o',' ','w','o','r','l','d'}
Теперь мы предоставили пространство, в котором символы должны быть сохранены, объявив s1
в качестве массива.
Обратите внимание, что вы можете использовать инициализацию привязки указателей, например, например:
char* c2 = {nullptr};
Однако, хотя синтаксис кажется равным, это нечто совершенно другое, которое называется равномерной инициализацией и просто инициализирует c2
с помощью nullptr
.
Ответ 2
В вашем первом случае строковый литерал распадается на указатель на const char. Хотя s1
действительно должен быть const char *
, несколько компиляторов разрешают другую форму как расширение:
const char* s1 = "hello world" ;
Лист литерала является массивом const char
, это видно из черновик проекта С++ 2.14.5
Строковые литералы, в котором говорится (акцент мой вперед):
Также указываются обычные строковые литералы и строковые литералы UTF-8 как узкие строковые литералы. Узкий строковый литерал имеет массив type n const char
",, где n - размер строки, как определено ниже, и имеет статическую продолжительность хранения (3.7).
Преобразование массива в указатель описано в разделе 4.2
Преобразование массива в указатель, в котором говорится:
[...] выражение, которое имеет тип '' массив типа, преобразуется в выражение с типом '' указатель на тип, указывающий на начальный элемент объекта массива и не является lvalue. [...]
Ваши другие случаи не работают, потому что скаляр, который может быть арифметическим типом, типами перечисления или типом указателя, может быть инициализирован только одним элементом внутри фигурных скобок, который описан в черновом стандартном разделе С++ 5.17
Операторы присваивания и составного присваивания 8.5.1
Пункт 3 инициализации списка, в котором говорится:
Список-инициализация объекта или ссылки типа T определяется как следующим образом:
а затем перечисляет различные случаи, единственное, что применимо к правой стороне для этого случая, - это следующая марка:
В противном случае, если в списке инициализаторов есть один элемент типа E и либо T не является ссылочным типом, либо его ссылочный тип ссылка, связанная с E, объект или ссылка инициализируются из этот элемент; если сужение конверсии (см. ниже) требуется для преобразуйте элемент в T, программа плохо сформирована.
который требует, чтобы список имел один элемент, в противном случае применяется конечная марка:
В противном случае программа плохо сформирована.
В двух случаях, даже если вы уменьшили инициализатор до одной переменной, типы неверны
h
является char и 2
является int
, который не будет преобразован в указатель.
Назначение может быть выполнено для работы, назначив результаты массиву, например:
char s1[] = { 'h', 'e', 'l', 'l', 'o',' ', 'w', 'o', 'r', 'l', 'd' } ;
int a[] = { 2, 3, 1, 45, 6 } ;
Это будет описано в разделе 8.5.1
Агрегаты, в котором говорится:
Массив неизвестного размера, инициализированный скобкой список инициализаторов, содержащий n инициализатор-предложений, где n должно быть больше нуля, определяется как имеющее n элементов (8.3.4). [Пример:
int x[] = { 1, 3, 5 };
объявляет и инициализирует x как одномерный массив, который имеет три элементов, поскольку размер не указан, и есть три инициализатора. -end example] Пустой список инициализаций {} не должен использоваться как initializer-clause для массива неизвестной границы .104
Примечание:
Неверно сказать, что список указателей скобок не определен для указателей, он отлично подходит для указателей:
int x = 10 ;
int *ip = &x ;
int *a = {nullptr} ;
int *b = {ip} ;