Код:
#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
У меня следующие два сомнения:
Как я могу сохранить строку без выделения памяти для нее. str
является символьным указателем и указывает, где переменная char i
, Когда я добавлю str = "Hello";
я не использую 5
байты из этого места 4
из которых не выделены?
С тех пор, я код str = &i;
не должен str
а также &i
имеют то же значение, когда я печатаю их? Когда я удаляю str = "Hello";
заявление str
а также &i
такие же. И если str
а также &i
то же самое, то я верю, когда я говорю str = "Hello"
это должно переписать 'a'
с 'H'
и остальное 'ello\0'
войти в последующие байты.
Я считаю, что вся проблема с str = "Hello"
заявление. Кажется, это не работает так, как я думаю.
Пожалуйста, кто-нибудь объясните, как это работает ??
Когда компилятор встречает строковый литерал, в этом случае "Hello"
, память выделяется в области статической (глобальной) памяти. Это «распределение» выполняется до выполнения вашей программы.
Когда ваша программа начинает выполняться в main
кадр стека выделяется для хранения локальных переменных main
: str
а также i
, Обратите внимание, что str
простая переменная, которая просто хранит адрес Он не хранит никаких символов. Он просто хранит указатель.
Заявление str = &i;
записывает в переменную str
адрес i
,
Заявление str = "Hello"
записывает в переменную str
, адрес строкового литерала "Hello"
который был предварительно выделен компилятором. Это совершенно другой адрес, чем адрес i
, Это назначение нигде не перемещает символы в слове «Hello».
TL; DR значение «строковой» переменной в C является просто указателем. Присвоение строковой переменной присваивает номер, а именно адрес.
Компилятор записывает последовательность байтов {‘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».
Когда я говорю str = «Hello», я не использую 5 байтов из этого местоположения 4
из которых не выделены?
Нет. Компилятор выделяет 6 байтов (помните нулевой терминатор) в другой части памяти (часть только для чтения, но это ответ на другой вопрос). Назначение:
str = "Hello";
причины str
указать расположение первого из этих 6 байтов, H
,
Так как я сказал, что str = i; не должно быть и &у меня такое же значение, когда я
печатать их?
Да, но вы установили str
чтобы указать на что-то еще в следующей строке, прежде чем печатать что-либо.
Буквенная строка "Hello"
занимает где-то 6 байт памяти, вероятно, в программном пространстве. Назначение указателя на него просто устанавливает указатель на то, где строка уже существует. Он не копирует символы вообще.
Если вы хотите скопировать символы, вам нужно использовать strcpy
, но так как вы не установили указатель на доступный для записи буфер достаточного размера, это приведет к неопределенному поведению, если вы это сделаете.
str
это указатель на символ Когда ты сказал str = &i;
Вы указываете это на Int. Когда ты сказал str = "Hello";
Вы меняете str, чтобы указать место, где хранится последовательность символов ‘H’, ‘e’, ’l’, ‘l’, ‘o’, 0.
Но вы говорите str = something else
сразу после того, как вы говорите str = &i
Похоже, вы еще не совсем поняли указатели …
Хорошо, проще говоря, каждая строка является указателем на 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
,
Во-первых, как я могу сохранить строку без выделения памяти для нее. str является указателем chracter и указывает, где хранится символ i. Когда я говорю str = «Hello», не использую ли я 5 байтов из этого местоположения, 4 из которых не выделены?
Память для строки выделяется компилятором. Я не думаю, что стандарт точно определяет, как компилятор должен это делать. Если вы запускаете «строки» для вашего исполняемого файла, вы должны найти где-нибудь «Hello».
Так как я сказал, что str = i; не должно быть и &у меня такое же значение, когда я печатаю их? Когда я удаляю оператор str = «Hello», str и &я такой же А если ул а &я такой же, тогда я верю, что когда я говорю str = «Hello», он должен перезаписывать ‘a’ на ‘H’, а остальные слова ‘ello \ 0’ входят в последующие байты.
Я думаю, что вам здесь не хватает, так это то, что str = «Hello» не копирует строку в место, на которое указывает str. Это меняет то, на что указывает str. «Привет» находится в памяти, и вы назначаете эту область памяти указателю. Если вы хотите скопировать память на указатель, вам нужно использовать memcpy () или что-то подобное.