char * str; ул = & Quot; ЗДРАВСТВУЛТ & Quot ;; Как это работает без выделения памяти для строки?

Код:

    #include <stdio.h>
int main() {
char *str;
char i = 'a';
str = &i;
str = "Hello";
printf("%s, %c, %x, %x", str, i, str, &i);
return 0;
}

Я получаю этот вывод:

Hello, a, 403064, 28ff0b

У меня следующие два сомнения:

  1. Как я могу сохранить строку без выделения памяти для нее. str является символьным указателем и указывает, где переменная char i, Когда я добавлю str = "Hello"; я не использую 5 байты из этого места 4 из которых не выделены?

  2. С тех пор, я код str = &i; не должен str а также &i имеют то же значение, когда я печатаю их? Когда я удаляю str = "Hello"; заявление str а также &i такие же. И если str а также &i то же самое, то я верю, когда я говорю str = "Hello" это должно переписать 'a' с 'H' и остальное 'ello\0' войти в последующие байты.

    Я считаю, что вся проблема с str = "Hello" заявление. Кажется, это не работает так, как я думаю.

Пожалуйста, кто-нибудь объясните, как это работает ??

3

Решение

Когда компилятор встречает строковый литерал, в этом случае "Hello", память выделяется в области статической (глобальной) памяти. Это «распределение» выполняется до выполнения вашей программы.

Когда ваша программа начинает выполняться в mainкадр стека выделяется для хранения локальных переменных main: str а также i, Обратите внимание, что str простая переменная, которая просто хранит адрес Он не хранит никаких символов. Он просто хранит указатель.

Заявление str = &i; записывает в переменную str адрес i,

Заявление str = "Hello" записывает в переменную str, адрес строкового литерала "Hello" который был предварительно выделен компилятором. Это совершенно другой адрес, чем адрес i, Это назначение нигде не перемещает символы в слове «Hello».

TL; DR значение «строковой» переменной в C является просто указателем. Присвоение строковой переменной присваивает номер, а именно адрес.

6

Другие решения

Компилятор записывает последовательность байтов {‘H’, ‘E’, ‘L’, ‘L’, ‘O’, ‘\ 0’} в раздел исполняемого файла, который называется сегмент данных.

Когда приложение запускается, оно берет адрес этих байтов и сохраняет их в переменной, представляющей ‘str’.

Он не должен «выделять» память в том смысле, что во время выполнения программе не нужно запрашивать у ОС память для хранения текста.

Вы должны стараться не воспринимать строковые литералы как неконстантные. Параметр GCC «-Wall» позволяет назначать строковые литералы указателям «char *» как

warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]

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

const char* str1 = "hello";
const char* str2 = "hello";

Если скомпилировано с пулами строк, исполняемый файл может содержать только один экземпляр «hello».

2

Когда я говорю str = «Hello», я не использую 5 байтов из этого местоположения 4
из которых не выделены?

Нет. Компилятор выделяет 6 байтов (помните нулевой терминатор) в другой части памяти (часть только для чтения, но это ответ на другой вопрос). Назначение:

str = "Hello";

причины str указать расположение первого из этих 6 байтов, H,

Так как я сказал, что str = i; не должно быть и &у меня такое же значение, когда я
печатать их?

Да, но вы установили str чтобы указать на что-то еще в следующей строке, прежде чем печатать что-либо.

1

Буквенная строка "Hello" занимает где-то 6 байт памяти, вероятно, в программном пространстве. Назначение указателя на него просто устанавливает указатель на то, где строка уже существует. Он не копирует символы вообще.

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

0
  1. str это указатель на символ Когда ты сказал str = &i; Вы указываете это на Int. Когда ты сказал str = "Hello"; Вы меняете str, чтобы указать место, где хранится последовательность символов ‘H’, ‘e’, ​​’l’, ‘l’, ‘o’, 0.

  2. Но вы говорите str = something else сразу после того, как вы говорите str = &i

Похоже, вы еще не совсем поняли указатели …

0

Хорошо, проще говоря, каждая строка является указателем на C.

Если мы бежим с этим:

int main() {
char *str;
char i='a';
str = &i;
str = "Hello";
printf("%s, %c, %x, %x", str, i, str, &i);
return 0;
}

Когда вы установите str = &i, ты делаешь str точка в i, Таким образом, i == *str а также &i == str держись

Когда вы звоните str = "Hello";, str теперь указывает на статически размещенный массив размера 6 (обычно он находится непосредственно в программном коде). Так как str является указателем, когда вы сбрасываете его, чтобы указать на новый массив, он не вносит изменений в i, Теперь, если вместо настройки str в "Hello", мы сделали *str = 'Z';, i теперь будет иметь значение «Z», в то время как str еще указывает на i,

0

Во-первых, как я могу сохранить строку без выделения памяти для нее. str является указателем chracter и указывает, где хранится символ i. Когда я говорю str = «Hello», не использую ли я 5 байтов из этого местоположения, 4 из которых не выделены?

Память для строки выделяется компилятором. Я не думаю, что стандарт точно определяет, как компилятор должен это делать. Если вы запускаете «строки» для вашего исполняемого файла, вы должны найти где-нибудь «Hello».

Так как я сказал, что str = i; не должно быть и &у меня такое же значение, когда я печатаю их? Когда я удаляю оператор str = «Hello», str и &я такой же А если ул а &я такой же, тогда я верю, что когда я говорю str = «Hello», он должен перезаписывать ‘a’ на ‘H’, а остальные слова ‘ello \ 0’ входят в последующие байты.

Я думаю, что вам здесь не хватает, так это то, что str = «Hello» не копирует строку в место, на которое указывает str. Это меняет то, на что указывает str. «Привет» находится в памяти, и вы назначаете эту область памяти указателю. Если вы хотите скопировать память на указатель, вам нужно использовать memcpy () или что-то подобное.

0