Почему я не могу создать массив 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' };
Другие вопросы по тегам