Почему я не могу создать массив int, используя 'const int*' так же, как 'const char*'?
Почему я могу создать строку или массив символов следующим образом:
#include <iostream>
int main() {
const char *string = "Hello, World!";
std::cout << string[1] << std::endl;
}
? и он выводит второй элемент правильно, в то время как я не могу сделать массив целочисленного типа без индексной записи массива [ ]
? В чем разница между этим символом и этим: const int* intArray={3,54,12,53};
,
4 ответа
"Почему" таково: "Потому что строковые литералы особенные". Строковый литерал хранится в двоичном виде как постоянная часть самой программы, и const char *string = "Hello, World!";
просто обрабатывает литерал как анонимный массив, хранящийся в другом месте, на который он затем сохраняет указатель в string
,
Не существует эквивалентного специального поведения для других типов, но вы можете получить то же базовое решение, сделав именованную статическую константу и используя ее для инициализации указателя, например,
int main() {
static const int intstatic[] = {3,54,12,53};
const int *intptr = intstatic;
std::cout << intptr[1] << std::endl;
}
Эффект от static const
Массив должен выделять то же постоянное пространство, которое будет использовать строковый литерал (хотя, в отличие от строковых литералов, менее вероятно, что компилятор будет определять дублирующиеся массивы и объединять хранилище), но как именованная переменная, а не анонимная. Строковый регистр может быть сделан явным таким же образом:
int main() {
static const char hellostatic[] = "Hello, World!";
const char *string = hellostatic;
std::cout << string[1] << std::endl;
}
но использование литерала напрямую делает вещи немного чище.
Такая особенность существует в C и называется составной литерал.
Например
#include <stdio.h>
int main(void)
{
const int *intArray = ( int[] ){ 3, 54, 12, 53 };
printf( "%d\n", intArray[1] );
return 0;
}
Однако C++ не поддерживает эту функцию из C.
Есть разница по сравнению со строковыми литералами. Строковые литералы имеют статическую продолжительность хранения независимо от того, где они появляются, в то время как составные литералы имеют либо статическую продолжительность хранения, либо автоматическую продолжительность хранения, в зависимости от того, где они появляются.
В C++ что-то похожее на эту функцию std::initializer_list
, Например
#include <iostream>
#include <initializer_list>
int main()
{
const auto &myArray = { 3, 54, 12, 53 };
std::cout << myArray.begin()[1] << std::endl;
return 0;
}
Ты почти можешь. Есть пара вещей на работе.
{1,2,3}
а также "abc"
это не одно и то же. На самом деле, если вы хотите провести сравнение, "abc"
лучше сравнивать с {'a', 'b', 'c', '\0'}
, Оба они являются действительными инициализаторами массива:
char foo[] = "abc";
char bar[] = {'a', 'b', 'c', '\0'};
Однако только "abc"
также является допустимым выражением для инициализации указателя в C++.
В C (и как расширение в некоторых компиляторах C++, включая Clang и GCC), вы можете приводить составные литералы к типу массива, например так:
static const int* array = (const int[]){1, 2, 3};
Однако это почти никогда не правильно. Он работает в глобальной области видимости и в качестве аргумента функции, но если вы попытаетесь инициализировать с его помощью переменную автоматического хранения (то есть переменную внутри функции), вы получите указатель на местоположение, которое скоро истечет, поэтому Вы не сможете использовать его для чего-нибудь полезного.
Литералы струн происходят от языка Си. Любая строка, объявленная в коде двойными кавычками, автоматически конвертируется как const char[].
Итак, это:
const char str[6] = "hello";
Точно так же, как:
const char str[6] = { 'h', 'e', 'l', 'l', 'o', '\0' };