Как char * освобождается в C

Итак, я читал код для класса, и я немного смущен тем, как переменная освобождается в C.

Приведенный код

#include<stdio.h>
main () {
    int n=0; 
    char *p = "hello world";
    while (*p!= 0)  {   // *p != '\0';
        putc(*p, stdout);
        p++;
    }
    printf("\np = %d", *p);
    printf("\np = %d\n", p);
}

Итак, я понял, что вам не нужно освобождать память для char *, так как никаких mallocs не происходит, но я не понимаю, почему этот код не будет пропускать какую-либо память... Если вы увеличиваете указатель на строку и, таким образом, перемещая указатель на следующий блок памяти (1 байт), не потеряете ли вы начальную ссылку и все контрольные точки, которые вы увеличиваете? Как бы эта память была восстановлена ​​без контрольной точки, если только она не будет сохранена компилятором до того, как этот тип операции произойдет. Я хотел бы получить некоторое представление о том, как это исправляется!

Ответ 1

Задача освобождения памяти накладывается на владельца этой памяти. Просто потому, что у вас есть указатель на какую-то область памяти, это не значит, что вы владеете этой памятью и, следовательно, не означает, что вы несете ответственность за ее освобождение.

Строковый литерал "hello world" - это объект со статической продолжительностью хранения. Он хранится в статической памяти. Статическая память всегда принадлежит среде выполнения. Среда выполнения знает данные, хранящиеся в статической памяти. Среда выполнения знает, когда эти данные должны быть освобождены (что легко, поскольку статическая память в основном "никогда" не освобождается - она ​​существует до тех пор, пока ваша программа работает).

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

Единственная память, которую вы можете иметь в программе C, - это память, которую вы лично выделили с помощью malloc (или других функций распределения динамической памяти). Итак, вы должны помнить, что в конечном итоге вызываете free для выделенной вами памяти (и вы должны убедиться, что знаете исходное значение, возвращаемое malloc, чтобы перейти к этому free). Все другие виды памяти (например, статические или автоматические) никогда не принадлежат вам, а это означает, что освобождение не является вашим бизнесом и сохранение исходных значений указателя совершенно не нужно.

Ответ 2

У вас нет утечки памяти, потому что вы не динамически выделяете какую-либо память. Утечки памяти происходят из-за освобождения динамически распределенной памяти. Локально выделенная память (например, char *p) или статически выделенная память (например, строка "hello world", изначально указывающая p) не может способствовать утечкам.

Ответ 3

Вы не динамически выделяете какую-либо новую память, поэтому вам не нужно ее освобождать.

Ответ 4

Строковый литерал "hello world" - это объект, который является частью самой программы. Когда выражение "hello world" оценивается, программа по существу получает указатель на кусок себя. Эта память не может быть освобождена во время работы программы; что эквивалентно созданию "дыры" в программе. Память имеет тот же срок службы, что и сама программа.

В языке C программисту не требуется управлять памятью, которая имеет такое же время жизни, как и программа: она управляется извне (или, как это может быть, неправильно) средой, которая запускает программу, и имеет дело с после завершения программы.

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

В программе, которая встроена, строковый литерал (вместе с остальной частью программы) может действительно жить в ПЗУ. Так что действительно ничего не может быть для очистки. Указатель - это адрес, который относится к некоторому постоянному местоположению на чипе (или нескольких чипах).

Ответ 5

Вкратце: потому что сама программа короткая. Вы можете сделать любой malloc, который вы хотите там, и никаких утечек не произойдет, поскольку вся память будет возвращена ОС, как только процесс завершится. Утечка не будет проблемой в вашем примере. Во всяком случае,

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

Ответ 6

Когда вы объявляете свои переменные локально, компилятор знает, сколько места требуется для каждой переменной, и когда вы запускаете свою программу, каждая локальная переменная (а также каждый вызов функции) помещается в стек. Сразу после утверждения return (или} скобки, если функция void), каждая локальная переменная выставляется из стека, поэтому вам не нужно ее освобождать.

Когда вы вызываете новый оператор (или malloc в чистом C), компилятор не знает размер данных, поэтому памяти выделяется время выполнения в куче.

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

Ответ 7

В дополнение к другим ответам, приращение указателя на C не создает или не теряет "ссылки", а также не вызывает никакого копирования или другого изменения памяти, на которое указывает указатель. Указатель в этом случае - это просто число, которое указывает на статически выделенную область памяти.

Приращение указателя не изменяет байты, на которые указывал указатель. "H", все еще существует. Но теперь программа думает, что строка начинается с "e". (Он знает, где конец строки, потому что строки конвенций в C заканчиваются на null.

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

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