Как работает char * blah = "hello"? - PullRequest
3 голосов
/ 01 июля 2010

Когда вы создаете строку из char указателей, как это работает?

char *name = "ben";

Арифметика "скрытого" указателя?

Ответы [ 7 ]

8 голосов
/ 01 июля 2010

Поскольку массивы автоматически распадаются на указатели.Это одностороннее преобразование.

В данном конкретном случае происходит то, что анонимный массив "ben" помещается компилятором в , вероятно, секцию данных только для чтения исполняемого файла (обычно .rodata in ELF ), а затем во время выполнения переменной name присваивается адрес первого байта в этом массиве.

6 голосов
/ 01 июля 2010

Арифметики скрытых указателей нет, но я подозреваю, что вам нужен более подробный ответ, чем этот.

Если у вас есть функция:

void foo() {
    char * bar = "Hello World";
}

На самом деле есть два блокапамяти, которая входит в игру:

  • Во-первых, 12 байтов используются для хранения «Hello World» (1 байт для каждой буквы плюс нулевой байт в конце).Компилятор поместит это в сегмент данных.Эта память (местоположение и значения) устанавливается во время компиляции и не может быть изменена во время выполнения (если вы попытаетесь, это приведет к segfault).
  • Второе местоположение - указатель на данные, это barпеременная.Когда ваша программа вызывает foo(), она выделяет достаточно стекового пространства (4 байта на 32 бита) для размещения этой области памяти, и она инициализируется с расположением фактических данных.Это происходит каждый раз, когда вы забавляетесь foo().

Более того, если вы выполните инструкцию, подобную этой, позже в функции:

bar = "Good bye";

Вы не меняете данные«Привет, мир», «До свидания».На самом деле вы просто получаете 3-й кусок памяти в сегменте данных с «Good bye» в нем (все еще выделяется во время компиляции), а затем указатель (bar) устанавливается в это место при выполнении этой строки.


Еще один метод создания «строк» ​​(символьных массивов):

void foo() {
    char bar[] = "Hello World";
}

Это не так же, как первый (хотя и закрытый).В этом методе у вас все еще есть две переменные, за исключением того, что фактические данные, о которых вы беспокоитесь («Hello World» + нулевой байт), выделяются и инициализируются в стеке программы.

Вы можете увидеть разницу вскомпилированную сборку, запустив gcc -S test.c и затем прочитав test.s.


В какой-то момент вам захочется взглянуть на строковые функции C .

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

4 голосов
/ 01 июля 2010

Строки в C - это просто смежные байты, расположенные в памяти и заканчивающиеся неявным байтом '\ 0'.Написав char * p = "string", вы просто загружаете адрес первого байта в этой последовательности в p.

Теперь для вашего точного вопроса предоставленный вами код выделит эту строку "ben" как четыре байта'b', 'e', ​​'n' и '\ 0' в статической памяти программы.Это означает, что строка не будет динамически размещаться в куче или автоматически в стеке.Он будет храниться в статическом разделе в вашем скомпилированном и связанном образе программы.Однако переменная-указатель name будет автоматически выделенной переменной стека, которая будет содержать адрес первого байта строки.

4 голосов
/ 01 июля 2010

Арифметика "скрытого" указателя?

Нет.Это явная арифметика с указателем в вашем лице.Вот что означает *.Указатель.

0 голосов
/ 01 июля 2010

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

0 голосов
/ 01 июля 2010

name - это просто указатель на первый адрес памяти, в данном случае «b» (или «h» в случае заголовка записи)Пустой символ вставляется в конце, чтобы обозначить конец строки.Так что не совсем указательная арифметика.

0 голосов
/ 01 июля 2010

Строка - это просто массив символов, который можно записать в виде:

char name[] = "ben";
...