C нулевой указатель со строковыми литералами - PullRequest
3 голосов
/ 17 марта 2011

Используя компилятор ARM, C, я могу успешно скомпилировать и запустить следующее:

static char * myString = 0;

void myfunc(int x){

   if (x <= 0)
       myString = "Hello World";
   else 
       myString = "This is a different string with a different length";

}

int main(){

    myfunc(-1);
    printf("%s\n", myString);
    myfunc(2);
    printf("%s\n", myString);
}

Почему это работает?

Разве указатель не должен быть указателем NULL?

По крайней мере, не должен ли строковый литерал размещаться в ячейке памяти, доступной только для чтения?

РЕДАКТИРОВАТЬ: это компилятор C ++

EDIT2: Почему строковый литерал существует в статической области видимости после того, как myfunc вышел из области видимости? Строковые литералы не объявлены в стеке? А когда их освобождают?

Спасибо!

Ответы [ 6 ]

7 голосов
/ 17 марта 2011

Две строки размещены в постоянной памяти и совершенно разные. Но вы используете один и тот же указатель, чтобы указать на каждого из них ... Что не понять?

Помните, char* это просто указатель. Это изменчиво (неконстантно).

char* p = 0;
p = "Hello"; //OK
p = "Jo" //OK;
p[0] = 'X' //OOPS, now THIS is bad (undefined behavior)

После редактирования:

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

3 голосов
/ 17 марта 2011

если бы вы объявили

char const *MyString = 0;  

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

       .section        .rodata
.LC0:
        .string "Hello World"
        .align 8
.LC1:
        .string "This is a different string with a different length"
        .text

Буквенные строковые данные собраны в разделе данных только для чтения.

2 голосов
/ 17 марта 2011

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

Я вполне уверен, что семантика четко определена в C.

Счастливого кодирования.

1 голос
/ 17 марта 2011

Да, но затем вы назначаете указатель на строковый литерал, поэтому он указывает на один из двух строковых массивов.

0 голосов
/ 17 марта 2011

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

0 голосов
/ 17 марта 2011

Изначально это нулевой указатель. Но вы сами явно меняете этот указатель и делаете его ненулевым внутри функции myfunc.

При первом вызове myfunc вы явно указываете указатель на строковый литерал "Hello World". После этого указатель, конечно, больше не равен нулю.

Строковые литералы действительно размещаются в области памяти только для чтения (по крайней мере, концептуально). Однако в C и C ++ вам разрешено указывать на строковые литералы с указателями char * (т.е. const char * не требуется) Можно просто указать на строковый литерал с указателем char *, если вы не пытаетесь изменить литерал. Ваш код не предпринимает никаких попыток что-либо изменить, поэтому все в порядке.

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

P.S. Чтобы ответить на ваш вопрос более полно, вы должны объяснить, почему на Земле вы ожидаете, что указатель останется нулевым.

P.P.S. int main, а не void main.

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