Выделите память и сохраните строку в c - PullRequest
21 голосов
/ 22 декабря 2011

Мне было интересно, почему следующий код не работает

int main(int argc, char **argv)
{
     char *test = (char*) malloc(12*sizeof(char));
     test = "testingonly";
     free(test);
}

Подумав об этом, я предположил, что сначала я выделяю пространство для 12 символов в памяти, но назначение в следующей строке создает символмассив в стеке и адрес памяти которого передается в тест.Таким образом, free () пытается освободить место в стеке, что недопустимо.Это правильно?

Так каков был бы правильный подход для сохранения строки в куче?Является ли следующий распространенным способом?

int main(int argc, char **argv)
{
     char *test = (char*) malloc(12*sizeof(char));
     strcpy(test, "testingonly");
     free(test);
}

Ответы [ 6 ]

65 голосов
/ 22 декабря 2011
char *test = (char*) malloc(12*sizeof(char));

        +-+-+-+-+-+-+-+-+-+-+-+-+
test--->|x|x|x|x|x|x|x|x|x|x|x|x|   (uninitialized memory, heap)
        +-+-+-+-+-+-+-+-+-+-+-+-+

test = "testingonly";

        +-+-+-+-+-+-+-+-+-+-+-+-+
test +  |x|x|x|x|x|x|x|x|x|x|x|x|
     |  +-+-+-+-+-+-+-+-+-+-+-+-+
     |  +-+-+-+-+-+-+-+-+-+-+-+-+
     +->|t|e|s|t|i|n|g|o|n|l|y|0|  
        +-+-+-+-+-+-+-+-+-+-+-+-+

free(test); // error, because test is no longer pointing to allocated space.

Вместо изменения указателя test, вам нужно скопировать строку "testingonly" в выделенное место, используя, например, strcpy или используйте strdup.Обратите внимание, что такие функции, как malloc и strdup возвращают NULL, если недостаточно памяти, и, следовательно, должны быть проверены.

char *test = (char*) malloc(12*sizeof(char));
strcpy(test, "testingonly");

        +-+-+-+-+-+-+-+-+-+-+-+-+
test--->|t|e|s|t|i|n|g|o|n|l|y|0|
        +-+-+-+-+-+-+-+-+-+-+-+-+

или

char *test = strdup("testingonly");

        +-+-+-+-+-+-+-+-+-+-+-+-+
test--->|t|e|s|t|i|n|g|o|n|l|y|0|
        +-+-+-+-+-+-+-+-+-+-+-+-+
8 голосов
/ 22 декабря 2011

Вы уже ответили на свой вопрос. По сути, strcpy является подходящим способом копирования строки.

5 голосов
/ 22 декабря 2011

Первая версия не создает строку в стеке, но вы правы, что вам не разрешено free ее после назначения. Строковые литералы обычно хранятся в постоянных / доступных только для чтения разделах памяти. Назначение ничего не копирует, просто заставляет test указывать на эту область памяти. Вы не можете освободить это. Вы также не можете изменить эту строку.

Ваш второй кусок кода правильный и обычный. Возможно, вы захотите взглянуть на strdup, если ваша реализация имеет это.

4 голосов
/ 22 декабря 2011

Ну, вы правы.Теперь давайте рассмотрим первый фрагмент кода.

char *test = (char*) malloc(12*sizeof(char));

Над кодом нет проблем.

test = "testingonly";

Здесь вы изменили указатель test, ведущий к утечке памяти.И когда вы пытаетесь освободить, вы освобождаете не фактический выделенный указатель, а один «тестирующий» литерал, указывающий на.Литерал указывает на постоянную память, которая не может быть переопределена в обычных сценариях.

Теперь о втором фрагменте кода, это будет работать нормально, если вы явно скопировали данные из того места, где находится литерал, в кучу, куда указывает test.

К вашему второму пункту да strcpy - это обычный способ.Другие способы - это memcpy, если вы копируете необработанные байты.

ПРИМЕЧАНИЕ. Литералы не хранятся в стеке.Но вы не можете изменить место, где хранятся литералы.

0 голосов
/ 02 января 2017

Это для выделения памяти:

char *string;
string = (char *) malloc(15);

Это для сохранения данных:

strcpy(str, "kavitajain");
printf("String = %s,  Address = %u\n", str, str);
0 голосов
/ 21 декабря 2015

код

#include <stdio.h>
int main(int argc, char **argv)
{
     char *test = (char*) malloc(12*sizeof(char));
     strcpy(test, "testingonly");
     printf("string is: %s\n",test);
     free(test);
     return 0;
}

будет работать

...