【发布时间】:2021-06-11 07:32:52
【问题描述】:
我正在读取文件,然后将其放入结构中。在阅读名称时,我也在检查重复名称,然后测试他们的 ID 是否大于另一个。如果它更大,那么我将向下移动更大的条目 ID 以替换它,然后释放较小的条目 ID。但是,当我释放较小的条目 ID(我不想要的那个)时,它会释放两个内存位置。
下面我的 GDB 测试器更详细地显示了我的内存位置问题:
89 cards[upd_j - 1] = cards[j];
1: cards[0]->name = 0x55555555a688 "Stolen by the Fae"
2: cards[1]->name = <error: Cannot access memory at address 0x10>
3: cards[2]->name = 0x55555555a898 "Eternal Isolation"
4: cards[3]->name = <error: Cannot access memory at address 0x91>
5: cardsaccum = 2
6: j = 2
7: num_entries = 3
8: upd_j = 2
(gdb) n
91 free(cards[upd_j]->start);
1: cards[0]->name = 0x55555555a688 "Stolen by the Fae"
2: cards[1]->name = 0x55555555a898 "Eternal Isolation"
3: cards[2]->name = 0x55555555a898 "Eternal Isolation"
4: cards[3]->name = <error: Cannot access memory at address 0x91>
5: cardsaccum = 2
6: j = 2
7: num_entries = 3
8: upd_j = 2
(gdb) n
92 free(cards[upd_j]);
1: cards[0]->name = 0x55555555a688 "Stolen by the Fae"
2: cards[1]->name = 0x55555555a898 "\020\220UUUU"
3: cards[2]->name = 0x55555555a898 "\020\220UUUU"
4: cards[3]->name = <error: Cannot access memory at address 0x91>
5: cardsaccum = 2
6: j = 2
7: num_entries = 3
8: upd_j = 2
这是我的结构:
typedef struct card
{
char* start;
unsigned int id;
char* name;
char* cost;
unsigned int converted_cost;
char* type;
char* text;
char* stats;
enum rarity rarity;
} card_t;
代码:
#include "card.h"
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
void parser(struct card **cards,int i, char *pointer);
// FUNCTION FOR QSORT()
int cmpname (const void *pa, const void *pb) {
const card_t * const *p1 = pa;
const card_t * const *p2 = pb;
return strcmp((*p1)->name, (*p2)->name);
}
// FOR OUTPUTTING THE RARITY WITH A CHAR
const char *rarities[] = { "common", "uncommon", "rare", "mythic" };
int main(int argc, char **argv) {
int padding;
ssize_t result;
int num_entries = 0;
int i = 0;
int cardsaccum = 0;
int boolean;
FILE *input_file;
if((input_file = fopen(argv[1], "r")))
{
card_t **cards = malloc(sizeof(*cards));
// getline() STORES THE LINE IN BUF
char *buf = NULL;
size_t bufsiz = 0;
// SKIPS HEADER LINE
getline(&buf, &bufsiz, input_file);
// WHILE THE FILE STILL HAS TEXT
while ((result = getline(&buf, &bufsiz, input_file)) != -1)
{
//if (boolean != 1)
//{
num_entries++;
// ALLOCATES MEMORY
cards = realloc(cards, sizeof(*cards) * num_entries);
cards[cardsaccum] = malloc(sizeof(card_t));
//}
boolean = 0;
// STORE CHARACTERS OF BUF IN ARRAY
char *array = strdup(buf);
// MAKE COPY OF ARRAY TO MAKE CHANGES TO
char *stringp = array;
// COPIES MEMORY ADDRESS TO FREE LATER ON
cards[cardsaccum]->start = array;
// SEPERATES FILE WHEN , IS FOUND
cards[cardsaccum]->id = atoi(strsep(&stringp, ","));
stringp++;
cards[cardsaccum]->name = strsep(&stringp, "\"");;
//TESTING FOR DUPLCIATES
for (int j = 0; j < cardsaccum; j++)
{
//CHECK IF CURRENT = PREVIOUS
if (strcmp(cards[cardsaccum]->name, cards[j]->name) == 0)
{
// ID > THAN PREVIOUS?
if(cards[cardsaccum]->id > cards[j]->id)
{
// FREE CARD AT POSITION J
free(cards[j]->start);
free(cards[j]);
cards[j] = NULL;
// GET THE REST OF THE INFO FOR THE CORRECT ENTRY
parser(cards,cardsaccum, stringp);
j++;
int upd_j = j;
// FREEING THE LESSER CARD ID
cards[upd_j - 1] = cards[j];
free(cards[upd_j]->start);
free(cards[upd_j]);
cards[upd_j] = NULL;
// NO NEED TO ACCUM SINCE WE FREED ONE CARD
num_entries--;
}
else
{
free(cards[cardsaccum]->start);
free(cards[cardsaccum]);
cards[cardsaccum] = NULL;
num_entries--;
}
// IF DUPLICATE IS FOUND, SET BOOLEAN TO 1
boolean = 1;
break;
}
}
// IF NOT DUPLICATE
if (boolean != 1)
{
parser(cards,cardsaccum,stringp);
cardsaccum++;
}
}
if(boolean == 1)
{
cards[cardsaccum] = NULL;
}
// QSORT
qsort(cards, cardsaccum, sizeof(*cards), cmpname);
for(i = 0; i < cardsaccum;i++)
{
padding = strlen(cards[i]->name);
padding = 51 - padding;
printf("%-s %*s\n", cards[i]->name, padding, cards[i]->cost);
printf("%-*s %*s\n", 43, cards[i]->type, 8, rarities[cards[i]->rarity]);
printf("----------------------------------------------------\n");
printf("%s \n", cards[i]->text);
printf("----------------------------------------------------\n");
printf("%*s\n", 52, cards[i]->stats);
printf("\n");
}
for(i = 0; i < cardsaccum; i++)
{
free(cards[i]->start);
}
for(i=0; i < cardsaccum ;i++)
{
free(cards[i]);
}
free(buf);
free(cards);
// CLOSING FILE
fclose(input_file);
return 0;
}
else
{
fprintf(stderr, "./parser: cannot open(%s%s%s): No such file or directory\n", "\"", argv[1], "\"");
return 1;
}
}
【问题讨论】:
-
您是否尝试过使用 gdb 逐步检查会发生什么?你能分享一个触发问题的输入文件吗?
-
我没有详细调查你的代码,所以我不知道错误发生在哪里,但我认为如果你按顺序执行代码会更容易:(1)阅读所有卡片,现在不关心重复。 (2) 按名称对卡片进行排序。无论如何,你都会这样做。现在所有相同的卡片都彼此相邻。 (3) 遍历数组并对其进行过滤,以便您只保留相同卡片块中的最高 id。 (您可以扩展您的排序标准,以便对于相等的字符串,最高 ID 始终是第一张卡片。)
标签: arrays c memory struct allocation