C "string" init - что лучше? - PullRequest
       1

C "string" init - что лучше?

2 голосов
/ 25 октября 2011

В чем разница между этими двумя инициализациями?

char a[] = "string literal";

char *p  = "string literal";

Ответы [ 5 ]

17 голосов
/ 25 октября 2011

Хотя эти два вида похожи и часто используются взаимозаменяемо, они означают разные вещи.Первая строка:

char a[] = "string literal"; 

... создает массив, достаточно большой для размещения строкового литерала, включая его терминатор NUL.Он инициализирует этот массив указанным строковым литералом.Одним из преимуществ этой версии является то, что массив может быть изменен позднее.Кроме того, размер массива известен даже во время компиляции, поэтому вы можете использовать оператор sizeof для определения его размера.Например:

printf("%u\n",unsigned(sizeof(a))); // Will display 15, which is the array's size 
                                    // including the NUL terminator

Вторая строка:

char *p  = "string literal"; 

... просто устанавливает указатель, указывающий на строковый литерал.Это быстрее, чем в первой версии, но у вас есть недостаток, заключающийся в том, что литерал не следует изменять, поскольку он может находиться на странице, помеченной как доступная только для чтения.У вас также есть недостаток, заключающийся в том, что для определения длины строки вам потребуется использовать функцию strlen(), поскольку оператор sizeof просто даст вам размер переменной-указателя.Например:

printf("%u\n",unsigned(sizeof(p))); // Will likely display 4 or 8, depending on
                                    // whether this is a 32-bit or 64-bit build
printf("%u\n",unsigned(strlen(p))); // Will display the correct length of 14, not
                                    // including the NUL terminator

Что лучше, зависит от того, что вы будете делать с этими переменными.Если вам не нужно вносить какие-либо изменения в строку, используйте более позднюю версию, но do измените char * на const char *, чтобы случайно не попытаться внести изменения в символыуказал на.Если вы намереваетесь изменить данные, используйте прежнюю версию на основе массива, которая позволяет вносить изменения в массив после инициализации.

3 голосов
/ 25 октября 2011

Каждый заставляет компилятор создавать строковый литерал в статической памяти, который (по крайней мере, концептуально) доступен только для чтения.

Первый затем использует это для инициализации содержимого массива. Строковый литерал просто используется, чтобы выбрать его размер и инициализировать его.

Второй создает указатель непосредственно на исходный строковый литерал.

Между ними нет ничего лучше или хуже. Они просто разные. Например, массив обычно использует больше памяти (есть строковый литерал, тогда в вашем массиве есть полная копия строкового литерала). Однако, поскольку это обычный нормальный массив, вы можете изменить его при необходимости.

Указатель непосредственно на строковый литерал часто экономит некоторую память. Это также означает, что вы можете назначить другое значение указателю, чтобы он (например) указывал на разные строковые литералы в разное время. Вы не , однако можете изменять данные, на которые он указывает - это приведет к неопределенному поведению.

0 голосов
/ 25 октября 2011

Один дает вам массив, заполненный указанными вами данными, второй дает вам указатель на некоторую память (обычно только для чтения) где-то, содержащую данные, которые вы указали.

Чтобы сделать разницу в "что вы получите "более ясно, попробуйте это:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
  char a[] = "string literal";
  char *b = "string literal";

  printf("a is %lu bytes, b is %lu\n", (unsigned long) sizeof a,
                                       (unsigned long) sizeof b);

  return EXIT_SUCCESS;
}

Вот демоверсия с приведенным выше кодом.

0 голосов
/ 25 октября 2011

Первый объявляет массив и заполняет его (устанавливая элементы один за другим, пока не будет включен конечный нулевой байт). Массив можно изменить.

Второй объявляет указатель и заполняет его, устанавливая его в константный литерал. Вы можете изменить указатель (например, чтобы он указывал в другом месте), но вы не можете изменить указанную им константную строку (которая в большинстве систем будет помещена в сегмент только для чтения).

0 голосов
/ 25 октября 2011

Зависит от того, что вам нужно.

char a[] = "string literal";

Создает изменяемый массив символов с автоматической продолжительностью хранения.Это допустимо:

a[0] = 'c';

С другой стороны ...

char *p  = "string literal";

Создает указатель на память только для чтения.Объявление действительно должно быть

const char *p  = "string literal";

Вы не можете юридически изменить то, на что указывает p.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...