Это появилось в проекте для класса. Вопрос может быть слишком длинным, но, поскольку я не знаю, где именно проблема, возможно, было бы полезно извлечь его в полном объеме.malloc, calloc и динамические массивы
Допустим, мы имеем структуру вида:
typedef struct
{
char *name;
char **friends;
int numFriends;
} User;
И у нас есть некоторый контейнер для структуры:
typedef struct
{
User *users;
int db_size;
} DB;
У нас также есть две функции для управления друзьями:
void makeFriends(char *name1, char *name2, DB *db)
{
User user1 = findByName(name1);
User user2 = findByName(name2);
user1.friends[numFriends] = name2;
user2.friends[numFriends] = name1;
user1.numFriends++;
user2.numFriends++;
update_db(user1, db);
update_db(user2, db);
}
void unmakeFriends(char *name1, char *name2, DB *db)
{
User user1 = getByName(name1);
User user2 = getByName(name2);
for (int i = 0; i < user1.numFriends; ++i)
{
if (strcmp(user1.friends[i]), name2)
{
int size = 0;
char *newFriendList = malloc(APPROPRIATE_AMOUNT);
for (int j = 0; j < count; ++i)
{
if (j != i)
{
newFriendList[size] = user1.friends[j];
size++;
}
}
user1.friends = newFriendList;
user1.numFriends = size;
// this breaks things for some reason
//free(newFriendList);
}
}
// and the same for user2
for (int i = 0; i < user2.numFriends; ++i)
{
if (strcmp(user2.friends[i]), name2)
{
int size = 0;
// this can lead to the corruption of user1's list
// char *newFriendList = malloc(APPROPRIATE_AMOUNT);
// but this works fine
char *newFriendList = calloc(someNum, APPROPRIATE_AMOUNT);
for (int j = 0; j < count; ++i)
{
if (j != i)
{
newFriendList[size] = user2.friends[j];
size++;
}
}
user2.friends = newFriendList;
user2.numFriends = size;
// this breaks things for some reason
//free(newFriendList);
}
}
update_db(user1, db);
update_db(user2, db);
}
Мы создаем трех пользователей, указывая им имя и выделяя некоторую память для их списка друзей:
User vladimir = { .name = "Vladimir", .friends = malloc(APPROPRIATE_AMOUNT), 0 };
User estragon = { .name = "Estragon", .friends = malloc(APPROPRIATE_AMOUNT), 0 };
User pozzo = { .name = "Pozzo", .friends = malloc(APPROPRIATE_AMOUNT), 0};
Теперь, скажем, Владимир и Эстрагон хотят стать друзьями, а затем Эстрагон и Поццо также становятся друзьями. Проходит время, и Владимир и Эстрагон решают, что они не очень любят друг друга, поэтому один из них недружелюбив другого.
Если я запускаю функцию unmakeFriends
и использовать malloc
дважды список первого пользователя друзей повреждается (например, имена появляются дважды или другим непредсказуемым поведением) во время второго цикла. Если я использую calloc дважды, я получаю это или ошибки шины. Если я попытаюсь освободить память, я получаю ошибки шины. Если я использую код так, как сейчас, один как malloc
, другой как calloc
, он работает по назначению.
Что происходит и почему?
Вам необходимо создать связанный список друзей, чтобы вы могли взять один из середины списка. Каждая запись в списке имеет выделенную/освобожденную память, а остальные записи остаются в силе. Google "связанный список c учебник". – Floris