提问人:ni1 提问时间:4/29/2023 最后编辑:Jonathan Lefflerni1 更新时间:5/1/2023 访问量:54
C.无法处理,我需要建议
fatal heap corruption error in c. cant handle it and i need advice
问:
我编写了一个使用结构和动态内存分配的程序。我想得到帮助,理解为什么如果我按 4(这意味着退出菜单)我会收到错误:检测到堆损坏:在 0x00845EE8 的正常块 (#76) 之后。它链接到函数 .我真的不明白为什么会这样以及如何解决这个问题。deletelist()
这是代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PRO_OP 1
#define CON_OP 2
#define PRINT_OP 3
#define EXIT_OP 4
#define STR_LEN 50
#define MAX_LIST_LENGTH 10
typedef struct reasonList
{
char* listName;
char* reasons[MAX_LIST_LENGTH];
int numReasons;
} reasonList;
void initList(reasonList* list, char* name);
void addReason(reasonList* list);
void printList(reasonList list);
int menu(void);
void myFgets(char str[], int n);
void deleteList(reasonList* list);
int main(void)
{
char dillema[STR_LEN] = { 0 };
int op = 0;
reasonList proList;
initList(&proList, "PRO");
reasonList conList;
initList(&conList, "CON");
printf("What is your dillema?\n");
myFgets(dillema, STR_LEN);
while (op != EXIT_OP)
{
op = menu();
switch (op)
{
case(PRO_OP):
addReason(&proList);
break;
case(CON_OP):
addReason(&conList);
break;
case(PRINT_OP):
printf("Your dillema:\n");
printf("%s\n\n", dillema);
printList(proList);
printList(conList);
break;
case(EXIT_OP):
deleteList(&proList);
deleteList(&conList);
break;
}
}
printf("Good luck!\n");
getchar();
return 0;
}
/*
Function will initialize a reason list
input: the list to init, and its name
output: none
*/
void initList(reasonList* list, char* listName)
{
list->listName = (char*) malloc(sizeof(char));
strcpy(list->listName, listName);//equal to PRO or CON
for (int i = 0; i < MAX_LIST_LENGTH; i++)
{
list->reasons[i] = (char*)malloc(sizeof(char) * STR_LEN);
if (list->reasons[i] == NULL)
{
printf("no memmory left\n");
exit(1);
}
strcpy(list->reasons[i], "");
}
list->numReasons = 0;
}
/*
Function will add a reason to the list
input: the list to add to and its name
output: none
*/
//
void addReason(reasonList* list)
{
char* newReason = (char*)malloc(sizeof(char) * STR_LEN);
printf("Enter a reason to add to the list %s:\n", list->listName);
myFgets(newReason, STR_LEN);
if (list->numReasons >= MAX_LIST_LENGTH)//if no memory left
{
//free(newReason);
return;
}
free(list->reasons[list->numReasons]);
list->reasons[list->numReasons] = newReason;
list->numReasons++;
list->reasons[list->numReasons] = NULL;
}
/*
Function will print a list of reasons
input: the list
output: none
*/
void printList(reasonList list)
{
printf("list %s\n--------\n", list.listName);
for (int i = 0; i < list.numReasons; i++)
{
printf("%s", list.reasons[i]);
printf("\n");
}
printf("\n");
}
/*
Function shows menu and returns user's choice
input: none
output: user's choice
*/
int menu(void)
{
int op = 0;
printf("Choose option:\n");
printf("%d - Add PRO reason\n", PRO_OP);
printf("%d - Add CON reason\n", CON_OP);
printf("%d - Print reasons\n", PRINT_OP);
printf("%d - Exit\n", EXIT_OP);
scanf("%d", &op);
while (op < PRO_OP || op > EXIT_OP)
{
printf("Invalid option. Try again: ");
scanf("%d", &op);
}
getchar(); // clean buffer
return op;
}
/*
Function will delete a list
input: the list to delete
output: none
*/
void deleteList(reasonList* list)
{
for (int i = 0; i < list->numReasons; i++)
{
free(list->reasons[i]);
list->reasons[i] = NULL; // set pointer to NULL
}
free(list->listName);
list->listName = NULL; // set pointer to NULL
}
/*
Function will perform the fgets command and also remove the newline
that might be at the end of the string - a known issue with fgets.
input: the buffer to read into, the number of chars to read
*/
void myFgets(char str[], int n)
{
fgets(str, n, stdin);
str[strcspn(str, "\n")] = 0;
}
答:
我无法重现段错误,但 valgrind 抱怨:它分配了 1 个字节(用于空字符串),而您需要.initList()
malloc(sizeof(char))
\0
strlen(listName) + 1
无关,为了消除内存泄漏,观察您在分配空间但只有空闲。建议你把它留给分配空间:initList()
MAX_LIST_LENGTH
reasons
deleteList()
list->numReasons
addReasons()
void initList(reasonList* list, char* listName) {
list->listName = malloc(strlen(listName) + 1);
strcpy(list->listName, listName);
list->numReasons = 0;
}
void addReason(reasonList* list) {
if (list->numReasons >= MAX_LIST_LENGTH)
return;
list->reasons[list->numReasons] = malloc(STR_LEN);
printf("Enter a reason to add to the list %s:\n", list->listName);
myFgets(list->reasons[list->numReasons++], STR_LEN);
}
如果您希望能够删除(和重用),那么您想要初始化,我建议(为了对称性)创建一个函数,然后在 .reasons[i]
initList()
list->reasons[i] = NULL
deleteReason()
deleteList()
另一个有效的设计(因为你是固定大小)是分配所有的输入(就像你一样)。在重用分配的字符串(no 或 )。在免费的所有原因。reasons
reasons
initList()
addReaon()
malloc()
free()
deleteList()
MAX_LIST_LENGTH
最好检查 的返回值。malloc()
不要强制转换 from .void *
malloc()
最好将与类型相反的变量传递给 。在上面而不是使用 或 sizeof *listNamesize(char)1',所以我总是把它省略掉。sizeof
sizeof(char)
sizeof *list->listName
; that said
is defined as
评论
list->listName = (char*) malloc(sizeof(char));
strcpy(list->listName, listName);//equal to PRO or CON
myFgets()
n
n
n-1
'\n'
gdb