какая разница между этими? - PullRequest
1 голос
/ 17 марта 2020

У меня есть эта функция, которая должна копировать узел в связанный список (не первый из него)

struct Node {
    char* data;
    Node* next;
};

void Insert(Node*head, int index, char* data) {//find a is function to find needed position
    Node* temp = find(head, index);
    Node* t = (Node*)malloc(sizeof(Node));
    t->data = (char*)malloc(100);//where the problem is //line 4
    strcpy(t->data, data);
    t->next = temp->next;
    temp->next = t;
}

, он будет работать хорошо, если строка 4 находится в моем коде. Я прочитал этот вопрос:

cra sh -или-ошибка-сегментации-когда-данные-копируются-сканируются-считываются-деинсталлируются

поэтому я знаю, что указатель не может содержать никаких данных, и я не могу скопировать / сохранить данные в указателе. Итак, как вы видите, я сначала выделил для него память, а затем поместил в нее данные, иначе моя программа обработает sh.

Но затем я использовал это: t->data = data;, и это сработало, поэтому я хочу знать: почему, когда я использую strcpy как этот strcpy(t->data, data);, мне нужно сначала выделить память для t->data, иначе моя программа потерпит крах; но это t->data = data; будет работать хорошо, без необходимости выделять память?

Можете ли вы объяснить это мне?

PS: приведение mallo c происходит из-за использования компилятора c ++.

Ответы [ 2 ]

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

Когда вы используете код t->data = data, вы не копируете какие-либо данные на свой узел! Все, что вы делаете, это заставляете data член узла указывать на данные, на которые также указывает аргумент функции - поэтому, если вы позже измените эти данные, то вы также измените данные узла. Это , вероятно, не , что вы собираетесь! Например, если вы вызываете функцию несколько раз «извне» и используете одну и ту же переменную для передачи данных, то каждый из добавленных вами узлов будет иметь data член, указывающий на один и тот же элемент данных.

Если вы действительно хотите скопировать данные из аргумента в ваш новый узел (как это делает ваш вызов strcpy), тогда вы должны сначала выделить для него место для хранения. с использованием (в вашем коде) функции malloc.

Но, как уже упоминалось в комментариях, функция strdup здесь гораздо удобнее: обе они выделяют (точное требуемое количество) памяти и копируют данные одним нажатием oop:

t->data = strdup(data);

Примечание. Память, выделенная strdup, должна быть освобождена (с вызовом free), когда вы с этим покончено, точно так же, как память, выделенная malloc.

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

Код выделяется только для размера указателя, когда необходим размер ссылочного объекта.

// Node* t = (Node*)malloc(sizeof(Node*));
Node* t = (Node*)malloc(sizeof(Node));

Еще лучше сопоставить размер ссылочного объекта, а не его тип. Приведение не требуется.

Node* t = malloc(sizeof *t);

Распределение строк также подозрительно. Вместо фиксированной 100 я бы ожидал распределение по размеру строки.

//t->data = (char*)malloc(100);
//strcpy(t->data, data);
size_t len = string(data);
t->data = malloc(len + 1);
strcpy(t->data, data);

Надежный код будет проверять ошибки распределения.

Node* t = malloc(sizeof *t);
if (t == NULL) Handle_OutOfMemory();
...