Базовое распределение памяти в стиле c - PullRequest
4 голосов
/ 16 ноября 2011

Я работаю над проектом с существующим кодом, который использует в основном C ++, но со строками в стиле c. Возьмите следующее:

#include <iostream>
int main(int argc, char *argv[])
{
    char* myString = "this is a test";
    myString = "this is a very very very very very very very very very very very long string";
    cout << myString << endl;
    return 0;
}

Это компилируется и работает нормально с выводом, являющимся длинной строкой.

Однако я не понимаю, ПОЧЕМУ это работает. Насколько я понимаю,

char* myString 

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

Очевидно, что есть базовое неправильное понимание того, что здесь происходит, поэтому я ценю любую помощь в понимании этого.

Ответы [ 6 ]

14 голосов
/ 16 ноября 2011

Вы не изменяете содержимое памяти, вы изменяете значение указателя так, чтобы оно указывало на другую область памяти, которая содержит "this is a very very very very very very very very very very very long string".

Примечание.char* myString выделяет только достаточное количество байтов для указателя (обычно 4 или 8 байтов).Когда вы делаете char* myString = "this is a test";, на самом деле происходит то, что до того, как ваша программа даже запускается , компилятор выделяет пространство в исполняемом образе и помещает "this is a test" в эту память.Затем, когда вы делаете char* myString = "this is a test";, на самом деле он просто выделяет достаточно байтов для указателя и указывает указатель на ту память, которую он уже выделил во время компиляции, в исполняемом файле.

Так что если вам нравитсядиаграммы:

char* myString = "this is a test";

(allocate memory for myString)

              ---> "this is a test"
            / 
myString---

                   "this is a very very very very very very very very very very very long string"

Тогда

myString = "this is a very very very very very very very very very very very long string";

                   "this is a test"

myString---
            \
              ---> "this is a very very very very very very very very very very very long string"
5 голосов
/ 16 ноября 2011

В памяти есть две строки.Сначала "this is a test", и предположим, что он начинается с адреса 0x1000.Второй "this is a very very ... test" и начинается с адреса 0x1200.

С помощью

char* myString = "this is a test";

вы создаете переменную с именем myString и присваиваете ей адрес 0x1000.Затем,

myString = "this is a very very ... test";

вы назначаете 0x1200.По

cout << myString << endl;

вы просто печатаете строку, начинающуюся с 0x1200.

2 голосов
/ 16 ноября 2011

Во время выполнения программы выделяется блок памяти, содержащий «это тест», а адрес первого символа в этом блоке памяти назначается переменной myString.В следующей строке выделен отдельный блок памяти, содержащий «это очень очень ...», и адрес первого символа в этом блоке памяти теперь назначен переменной myString, заменив адрес, который он использовал дляхранить с новым адресом в «очень очень длинной» строке.

только для иллюстрации, скажем, первый блок памяти выглядит так:

[t] [h] [i][s] [] [i] [s] [] [a] [] [t] [e] [s] [t], и давайте просто скажем адрес этого первого символа 't' в этой последовательности / массиве символов0x100.поэтому после первого присваивания переменной myString переменная myString содержит адрес 0x100, который указывает на первую букву «это тест».

затем совершенно другой блок памяти содержит:

[t] [h] [i] [s] [] [i] [s] [] [a] [] [v] [e] [r] [r] [y] ... идавайте просто скажем, что адрес этого первого символа 't' равен 0x200.поэтому после второго присваивания переменной myString переменная myString NOW содержит адрес 0x200, который указывает на первую букву «это очень очень очень ...».

Поскольку myString - просто указательдля символа (отсюда: «char *» - это его тип), он хранит только адрес символа;он не заботится о том, насколько большим должен быть массив, он даже не знает, что он указывает на «массив», только что он хранит адрес символа ...

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

    char myChar = 'C';
/* assign the address of the location in 
   memory in which 'C' is stored to 
   the myString variable. */
    myString = &myChar; 

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

2 голосов
/ 16 ноября 2011

У вас есть два строковых литерала типа const char[n]. Их можно назначить переменной типа char*, которая является не чем иным, как указателем на char. Всякий раз, когда вы объявляете переменную типа pointer-to-T, вы объявляете только указатель, а не память, на которую он указывает.

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

Теперь, было бы UB, если бы вы попытались изменить содержимое литерала, но это не так. Чтобы предотвратить попытки изменения ошибки, было бы разумно объявить переменную как const char*.

1 голос
/ 16 ноября 2011

строковые литералы не требуют выделения - они хранятся как есть и могут использоваться напрямую.По сути, myString был указателем на один строковый литерал и был изменен, чтобы указывать на другой строковый литерал.

0 голосов
/ 16 ноября 2011

char* означает указатель на блок памяти, который содержит символ.

Строковые функции в стиле C получают указатель на начало строки. Они предполагают, что есть последовательность символов, заканчивающаяся нулевым символом (\ n).

Так что оператор << на самом деле выполняет цикл от этой первой позиции символа до тех пор, пока не найдет нулевой символ. </p>

...