Прошу прощения за заданный основной вопрос, который определенно был задан раньше, но я просто не мог его найти! Почему в C вы можете назначить строковый литерал для char *, но не можете назначить целочисленный литерал для int *?Разница между char * и int *
ответ
Строка в C не является примитивным типом данных. Это фактически оконечная последовательность символов с нулем. Таким образом, char *sp = "literal";
фактически работает с указателем на последовательность символов.
Int с другой стороны является примитивным типом, поэтому, когда вы используете литерал int, это int без каких-либо трюков, чтобы сделать его похожим на что-то другое.
Это звучит разумно, но тогда почему я помню чтение (я думаю, на языке программирования C++), что они разрешали присваивать строковый литерал char *, потому что в предыдущих определениях C тип строкового литерала был char *, но сегодня, когда это технически тип char [], его не следует разрешать (но для обратной совместимости). – Yamor
ОП спрашивает о _string literal_, и в этом ответе обсуждается _string_. Похоже, но другое. «Строковый литерал не обязательно должен быть строкой (см. 7.1.1), потому что нулевой символ может быть встроен в него с помощью escape-последовательности \ 0." C11 сноска 78 – chux
@Yamor: в стандарте C ясно, что модификации результирующего массива с литералом являются неопределенным поведением. Тем не менее, это явно не 'const char []', поэтому назначение символу 'char *' четко определено. Хотя я согласен, что это проблематично, иногда полезно использовать строку по умолчанию. Это запрещено в C++. Обратите внимание, что C++ и C - разные языки. Портирование правил от одного к другому чаще всего является проблемой, чем ожидают многие люди. – Olaf
Поскольку строковый литерал переводится в массив char
(char []
) во время перевода. C не имеет определенного типа строки.
В каждом массиве, он преобразуется для большинства использований (для sizeof
, кроме _Alignof
а также адрес-оператор &
), он преобразуется («затухает») в указатель на его первый элемент. Поскольку это char *
, нет никакой проблемы с его назначением переменной char *
или передачей в качестве аргумента char *
.
int
/целочисленная константа (стандарт C не использует термин «литерал» здесь). OTOH можно преобразовать в указатель, но это не то, что вы обычно хотите. Также выполняется преобразование. Таким образом, компилятор выдает предупреждение для такого назначения без явного приведения. Чтобы подчеркнуть: очень мало случаев, когда вы хотите назначить целочисленную константу указателю (например, встроенным системам). Нет в обычных программах для ПК.
Чтобы получить адрес в int
переменной, используйте &
оператор:
int i = 5;
int *p = &i;
Если вам нужно что-то похожее на строковый литерал, квалифицирует переменной const
:
const int i = 5;
Примечание что это все еще одно целое, поэтому вы не должны добавлять смещение к указателю, например p[1]
- это неопределенное поведение.
Хороший ответ, кроме «C не имеет строкового типа». поскольку это смущает проблему, и ИМО не требуется. C определяет _string literal_ и _string_, но не определяет, что вы подразумеваете под типом _string_. – chux
@chux: Я добавил слово, чтобы уточнить. Но я думаю, что эта информация не является ни запутанной, ни ненужной. Как только вы согласитесь, что это просто «char []», и ничего больше, все становится намного яснее. Btw. 6.2.5 хорошо описывает концепцию типов. И термин «строка» используется только в контексте _string-literal_ или библиотек обработки строк. – Olaf
В C строка представляет собой массив символов. Когда массив используется как значение выражения, он обычно автоматически преобразуется в указатель на его первый элемент (есть некоторые исключения, они здесь не важны), поэтому вы можете назначить это переменной указателя.
Другие литералы не преобразуются автоматически в указатели, поэтому вы не можете назначать их указателям без кастинга (и даже если вы выполняете литье, результат не переносится). Так что причина, вы не можете сделать:
int *intptr = 123;
той же причине вы не можете сделать:
char *charptr = 'a';
Обратите внимание, что нет ничего особенного char*
. Вы можете назначить int*
из массива int
, например.
int intarray[] = {1, 2, 3};
int *intptr = intarray;
Это не совсем правильно. Массив не всегда преобразуется в «указатель ...». – Olaf
Когда он может использоваться как r-значение без преобразования? – Barmar
В стандарте C вообще не используется термин rvalue, но упоминается только один раз в сноске 64: _What иногда называют «rvalue» в этом Международном стандарте, описываемом как «значение выражения» _. См. Соответствующий раздел 6.3.2.1p3 за исключениями. – Olaf
Литература строки C представляет собой массив символов типа (состоит из множества символов). Целое число - это единственный элемент типа int.
Именно поэтому синтаксис для назначения каждого указателю отличается.
Назначение массива типа char или int указателю будет использовать тот же синтаксис, что и назначение одного элемента типа char или int указателю.
Когда вы говорите
char *str = "Hello";
что происходит, примерно такой же, как если бы вы сказали
const char tmpstr[] = {'H', 'e', 'l', 'l', 'o', '\0'};
char *str = tmpstr;
То есть, всякий раз, когда вы пишете строку постоянным, как «Hello», компилятор автоматически выделяет небольшой статический массив символов, содержащий вашу строку. И это вполне нормально использовать этот массив в качестве инициализатора для указателя на символ. (Там на самом деле потенциал немного несоответствие, чтобы, является ли строка постоянной массив сопзЬ полукокса или нет, но давайте не будем беспокоиться о том, что на данный момент.)
Так что, если вы сказали
int tmpi[] = {1, 2, 3, 4, 5};
int *ip = tmpi;
, что будет работать отлично, тоже.
Но вы не можете присвоить целое число к int *
, потому что не имеет смысла:
int *ip2 = 123; /* WRONG */
Справа мы имеем целое число 123, а слева мы имеем int *
, и вы не можете назначить целое число указателю.
(Теперь, если вы действительно хотите, вы можете попробовать присвоить необработанный адрес памяти для указателя, но давайте не будем беспокоиться о том, что на данный момент, либо.)
Стандарт намеренно не перехитрил сгенерированный массив 'const', но явно указывает, что изменения UB. В результате вы можете «char * p =« Hello »;', а 'const char a [] =" Hello "; char * p = a; 'должен генерировать предупреждение. Таким образом, вы не можете сделать его эквивалентным. – Olaf
@ Олаф: Конечно. Вот почему я сказал «просто * о» точно так же ». –
У него разные семантические преобразования - самая важная часть, а не только незначительная разница. – Olaf
- 1. Разница между int * a и char * a?
- 2. разница между int * и char * in C++
- 3. Разница между char ** и char [] []
- 4. Разница между char * и char []
- 5. Разница между const char [] и char []
- 6. разница между char * и char [] с strcpy()
- 7. Разница между 'int' и 'int?'
- 8. Разница между char var [] и char var [] []
- 9. Разница между char и char [1]
- 10. Разница между неподписанными символами char и char
- 11. Разница между char [] и char * in C
- 12. Разница между char * и const char *?
- 13. Разница между char [] и char * in C
- 14. Разница между char * var; и char * var ;?
- 15. В чем разница между (char *) и char *?
- 16. В чем разница между печатью char * с `&` и `(int *)`?
- 17. Разница между char и int при объявлении символа
- 18. разница между char * и string
- 19. Разница между char * s = new char [] и char s [20]?
- 20. Разница между char, char * внутри Связанные списки
- 21. В чем разница между int ++ и ++ int?
- 22. C++ Разница между 'int' и 'INT'
- 23. разница между преобразованием типов (INT **) и Int (*)
- 24. Разница между const int и int literal
- 25. Разница между Int() и Int: в Swift
- 26. разница между int * i и int * i
- 27. В чем разница между int [] [] и int [,]?
- 28. Разница между int * i и int ** i
- 29. В чем разница между [] int и int []
- 30. Разница между int cast и int & cast
Это неправильный вопрос. Правильный вопрос: «Почему я не могу назначить целочисленный литерал для« int * »и почему я также не могу назначить литерал символа символу' char * '. –
Вам нужен код, чтобы продемонстрировать, что вы пытаетесь сделать. В C вы можете что-то бросить. – Claris
Поскольку то, что вы называете «строковым литералом», фактически анализируется как постоянный массив символов. char * var = "string" - это то же самое, что и char var [] = {'s', 't', 'r', 'i', 'n', 'g'}; –