#c #struct
#c #struct
Вопрос:
Мои данные перезаписываются всякий раз, когда я вставляю новое значение, если я опускаю свой free() в основной программе, моя программа работает нормально.Почему ?Как устранить эту проблему.Правильно ли распределена память структуры?
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct List
{
char val[20] ;
};
struct Hashtable
{
struct List *start;
};
struct Hashtable ht[26];
void init();
void insert(struct List*);
void init()
{
register int j;
for (j=0;j<26;j )
{
ht[j].start=NULL;
}
}
int main(void)
{
init();
int i=0;
for (int i=0;i<5;i )
{
struct List *newnode=(struct List*)malloc(sizeof(struct List));
scanf("%s",newnode->val);
insert(newnode);
free(newnode);
newnode=NULL;
}
return 0;
}
void insert(struct List *node)
{
if ( ht[node->val[0]-97].start==NULL)
{
ht[node->val[0]-97].start=node;
return;
}
else
{
printf("The value is %sn", ht[node->val[0]-97].start->val);
}
}
————————————————————————————————————————————————-___________________________________________________________________________
Комментарии:
1. Вы выделяете узел, вставляете его в список, а затем немедленно освобождаете его. Поскольку вставка не выделяет копию узла (и без документации неясно, каким должно быть ожидаемое поведение), вы освобождаете то, что только что вставили.
2. Неопределенное поведение для доступа к объекту после окончания срока службы объекта.
3. Я понял .. мы копируем указатели, а не память.
Ответ №1:
Когда вы назначаете указатели, вы копируете только сами указатели, а не память, на которую они могут указывать.
При вызове free
с использованием указателя все копии этого указателя становятся недействительными и больше не могут использоваться.
Вам либо нужно создать совершенно новую копию в insert
функции (включая выделение новой List
структуры), либо вы не должны вызывать free
.
Моя личная рекомендация заключается в том, чтобы вы вообще не выделяли в main
функции, и чтобы insert
функция принимала строку для «вставки» в качестве аргумента (вместо List
указателя, который она принимает в данный момент).
Возможно, что-то вроде этого:
void insert(char *val)
{
// Get the hash-table index (note that it only works with ASCII encoding)
char hash = tolower(val[0]) - 'a';
// First check if it exists
if (ht[hash].start == NULL)
{
// No, then add it
// First allocate memory for the node
struct List *node = malloc(sizeof *node);
// Then copy the string
strcpy(node->val, val);
// And finally add it
ht[hash].start = node;
}
}
Тогда ваш цикл в main
функции может быть следующим
for (unsigned i = 0; i < 5; i)
{
char val[20];
scanf("s", val);
insert(val);
}
Ответ №2:
Представьте, что память — это ряд ячеек, каждая из которых содержит 8-битное значение и пронумерована как 1, 2, 3… (Ну, обычно более высокие значения, но вы это понимаете). Указатель — это просто номер этого шкафчика, не более того. Что делает malloc, так это:
- Найдите место со свободной памятью
- Отметьте эту память как используемую
- Возвращает номер первого шкафчика
Когда вы освобождаете, вы снова помечаете эту память как свободную. Для этого существует множество алгоритмов, но было бы разумно искать небольшое свободное пространство памяти с как можно меньшим его количеством, поскольку оставлять пустые места — пустая трата памяти.
Когда вы назначаете указатель, вы присваиваете не значения, на которые он указывает, а номер ячейки. Когда вы освобождаете, вы даете алгоритму возможность использовать этот шкафчик, и когда вы снова используете malloc, он, вероятно, находит тот же шкафчик, что и раньше, а затем вы изменяете его содержимое.
Помните, что ваша хэш-таблица по-прежнему использует этот номер ячейки, и когда она откроет ячейку, она обнаружит, что ее содержимое изменено.
Решение ниже:
TL; DR:
- Ваша хэш-таблица использует все ту же память, поэтому не освобождайте ее, поскольку она может быть изменена при обнаружении malloc.
- Освободите его от хэш-таблицы, как только вы закончите использовать этот указатель, чтобы избежать потери памяти
Примечание: Если вы только что прочитали решение, понимание heap (выше) поможет вам с множеством головных болей, плюс приятно знать, что компьютер делает с вашим кодом.