2014-12-22 1 views
3

Я не мог придумать правильное название для моего вопроса, так что вот оно. Я пытаюсь изучить C, и следующий код из учебника я следую.Дублирующие строки передаются в функции как параметры в C

struct Person { 
    char *name; 
    int age; 
    int height; 
    int weight; 
}; 

struct Person *Person_create(char *name, int age, int height, int weight){ 
    struct Person *who = malloc(sizeof(struct Person)); 
    assert(who != NULL); 

    who->name = strdup(name); 
    who->age = age; 
    who->height = height; 
    who->weight = weight; 

    return who; 
} 

void Person_destroy(struct Person *who){ 
    assert(who != NULL); 

    free(who->name); 
    free(who); 
} 

int main(int argc, char *argv[]){ 
    struct Person *joe = Person_create("Joe Alex", 32, 64, 140); 

    ........ 

Мой вопрос в Person_create функции, почему мы дублируя name на новое место памяти для who->name. Почему мы не можем просто сделать who->name точкой в ​​том же месте, что и *name.
Также, если мы прямо присвоили адрес *namewho->name, мы должны освободить его в Person_destroy.

+0

Предположим, что если вы сделали 'who-> name = name', то вы не измените' who-> name' последним, поскольку аргумент функции 'name' указывает на строковый литерал. как @ al-Acme также объяснил в своем ответе, –

+0

Как вызывается Person_create(). Откуда передается параметр 'name '? Как это создается? – zoska

+1

Спасибо всем за ответы и комментарии. – MiJo

ответ

6

Почему мы не можем просто указать who-> name в то же место, что и имя *, предоставленное функции.

Для меня это who->name = strdup(name); лучше, чем это who->name = name;, если я знаю, что будет изменять строку, на который указывает name позже где-то.

Таким образом, вы могли бы также сделать это:

who->name = name; 

Однако строковым как "Joe Alex" находится в месте, доступном только для чтения - так что если вы хотите сделать что-то вроде этого (позже в некоторой части ваш код):

who->name[3] = 'x'; 

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

Вы можете посмотреть на: Modifying String Literal

+1

Спасибо. Появилась идея. – MiJo

-2

полукокса массива *name не является распределенным массивом, это означает, что если вы оставите вашу область видимости функции, этот массив не может использоваться больше. Поэтому учебник копирует его, чтобы выполнять операции позже с этой переменной. Кроме того, если вы назначили свою переменную *name на номер who->name, вы не должны ее освобождать, так как она не была возвращена malloc.

+0

Это неверно, так как значение 'name' все еще можно использовать. Любая ссылка на переменную будет недействительной, а не ее значением. –

+0

@PhilippMurry Немного о том, чтобы освободить 'who-> name', если он был напрямую назначен с адресом' name', является правильным ?. Как упоминалось в ответе @ al-Acme, исходное «имя» не находится в куче. – MiJo

+0

Если это не на куче, то это правда. Как правило: для каждого вызова в malloc/calloc должен быть один бесплатный вызов. Не больше и не меньше. Так что, если это не на кучу, никогда не было вызова в malloc/calloc, и поэтому не нужно звонить бесплатно. –