2016-06-14 2 views
0

Я изучаю основ программирования на С и считаю это довольно странным и трудным. Особенно с динамическим распределением памяти, указателем и т. Д. Я столкнулся с этой функцией и не совсем понимаю, что с ней не так.Когда использовать функцию malloc?

char *strdup(const char *p) 
    { 
     char *q; 
     strcpy(q, p); 
     return q; 
    } 

Я думаю, что мне нужно malloc и бесплатно q. Но функция «return q». Разве это не означает, что он сохранит значение q в своей собственной памяти. Таким образом, данные сохраняются после выполнения функции?

Если уместно использовать malloc? Насколько я понимаю до сих пор, мне приходится менять новую переменную каждый раз, когда мне нужна эта переменная, объявленная в функции, которая будет использоваться в другом месте. Это правда? Есть ли другая ситуация, когда требуется malloc?

+0

Ну, посмотрите на вызов 'strcpy'. Он пытается скопировать строку, на которую указывает 'p', в массив, на который указывает' q'. За исключением 'q' не инициализируется, чтобы указывать на массив. Он содержит значение мусора, поэтому вы будете повреждать память, если вы это вызвали. Сначала вам нужно установить 'q' на адрес соответствующего блока хранения, например, что возвращает' malloc'. Только тогда вы сможете написать свою цель. Просто. –

+0

q - адрес, но он не инициализирован. strcpy пытается взять данные и поместить их в место, адресованное q, но q не указывает на что-либо действительное. Вызов malloc (и присвоение результата q) делает q указывать на место, где вы можете поместить данные. –

+0

* Реальная проблема заключается в том, что вам нужно узнать о сроках жизни. К сожалению, большинство учебных пособий обучают только синтаксису, а не важным темам. – o11c

ответ

4

Мои личные правила: используйте malloc(), когда объект слишком велик, чтобы положить на стек или/или когда он должен выходить за пределы текущего блока. В вашем случае, я полагаю, вы должны сделать что-то вроде следующего:

char *strdup(const char *p) 
{ 
    char *q; 
    q = malloc(strlen(p) + 1); 
    if(NULL != q) 
     strcpy(q, p); 
    return q; 
} 
5

Тип ц является указателем, а указатели держать адреса - так что вы возвращаете адрес, который имеет указатель.

Пока вы не укажете этот указатель действительным адресом, он указывает на то, кто знает, где, память, которую вы можете или не можете иметь и иметь право доступа. Таким образом, вызов strdup скопирует строку из адреса, содержащегося в p, в какое-то место, которое вы, вероятно, не имеете.

Если вы сначала сделали malloc и дали q результаты malloc, тогда q будет содержать действительный адрес, а ваш strdup поместит копию в память, которую вы сделали (если вы malloc'd достаточно места для строки - strlen on p расскажет вам, сколько вам нужно).

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

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

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

Другое типичное использование malloc - это создание динамических структур данных, таких как деревья и списки, - вы не можете знать, сколько памяти вам нужно спереди, поэтому вы создаете список или дерево, как вам нужно, malloc ' чем больше памяти для каждого узла в структуре.

0

malloc(X) создает пространство (размером X байт) в куче для вас, чтобы играть. Данные, которые вы пишете на эти байты X, остаются, когда ваша функция возвращается, в результате вы можете прочитать, какую функцию strdup() написал в это место в куче.

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

В части кода вы написали, что strcpy() функция копирует байт один по одному из p до q, пока он не найдет \0 на место, на который указывает q (а затем он копирует \0, а). Чтобы где-то записывать данные, вам необходимо сначала выделить пространство для данных, которые должны быть записаны, поэтому один из них - это то, что вы вызываете malloc(), чтобы создать некоторое пространство, а затем записать там данные.

Ну, называя free() не является обязательным, как операционная система будет восстановить пространство, выделенное на malloc(), когда программа завершается, но до тех пор, как ваша программа работает, вы можете быть ocupying больше места, чем нужно - и это плохо для вашей программы, для других программ, для ОС и вселенной в целом.

0

Я думаю, что мне нужно malloc и бесплатно q. Но функция «return q». Разве это не означает, что он сохранит значение q в своей собственной памяти. Таким образом, данные сохраняются после выполнения функции?

Нет, ваши данные не будут сохранены. Фактически, ваш указатель q используется без выделения его размера, может вызвать проблемы. Кроме того, после завершения этой функции переменная char * q будет уничтожена.

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

char *strdup(const char *p) // From @Michael's answer 
{ 
    char *q; 
    q = malloc(strlen(p) + 1); 
    if(NULL != q) 
     strcpy(q, p); 
    return q; 
} 

void someFunction() 
{ 
    char* aDupString = strdup("Hello World!!!"); 
    /*... somecode use aDupString */ 
    free(aDupString); // If not freed, will cause memory leaks 
} 

Когда это целесообразно использовать таНос? Есть ли другая ситуация, когда требуется malloc?

Это целесообразно использовать в следующих ситуациях:

1> Размер использования массива неизвестен во время компиляции.

2> Вам нужна гибкость по размеру. Например, ваша функция должна работать с небольшим размером данных и большим размером данных. (Например, структуры данных, такие как список ссылок, стеки, очереди и т.д.)

Как я понимаю, до сих пор является то, что я должен таНосом новым переменным каждый раза, когда мне нужно, что переменный, объявленные в функции будет используется в другом месте. Это правда?

Я думаю, что это частично верно. в зависимости от того, что вы пытаетесь достичь, возможно, есть способ обойти использование malloc.Например, ваш strdup можно также переписать следующим образом:

void strdup2(const char *p, char* strOut) 
{ 
    // malloc not require 
    strcpy(strOut, p); 
} 

void someFunction() 
{ 
    char aString[15] = "Hello World!!!"; 
    char aDupStr[sizeof(aString)]; 
    strdup2(aString, aDupStr); 

    // free() memory not required. but size is not dynamic. 
} 
Смежные вопросы