【发布时间】:2020-06-28 15:00:13
【问题描述】:
我最近刚开始学习 C,但在计算内存分配时遇到了问题。我花了大约最后 2~3 天的额外时间试图解决这个问题,但还没有找到解决方案。所以首先,我有两个结构:
struct _list {
// arr is an array of string arrays
char **arr;
// recs tracks how many records are in the list
size_t recs;
// arrSizes records the size of each string array in arr
size_t *arrSizes;
};
typedef struct _list list_t;
和
struct _string {
char *string;
// size is used to store strlen
size_t size;
};
typedef struct _string string_t;
我分别通过以下方式初始化上述结构体。
list_t:
list_t *NewList() {
list_t *List = NULL;
List = malloc(sizeof(*List));
if (List == NULL) {
fprintf(stderr, "Failed to allocate memory to list structure.\n");
return NULL;
}
List->arr = malloc(sizeof(List->arr));
if (List->arr == NULL) {
free(List);
fprintf(stderr, "Failed to allocate memory to list array.\n");
return NULL;
}
List->arrSizes = malloc(sizeof(List->arrSizes));
if (List->arr == NULL) {
free(List);
fprintf(stderr, "Failed to allocate memory to size array.\n");
return NULL;
}
List->recs = 0;
return List;
}
string_t:
// a string array read in by the program is passed with "char* record"
string_t *NewString(char *record)
{
string_t *String = NULL;
String = malloc(sizeof * String);
if (String == NULL) {
fprintf(stderr, "Failed to allocate memory to string structure.\n");
return NULL;
}
String->size = strlen(record) + 1;
String->string = malloc(String->size);
if (String->string == NULL) {
free(String);
fprintf(stderr, "Failed to allocate memory to string array.\n");
return NULL;
}
strcpy(String->string, record);
return String;
}
我从文件中读取行并将它们加载到“匹配结果”缓冲区中,使用类似于以下代码的内容。请忽略退出以及结构初始化完成后我没有空处理的事实;稍后我会添加一些更有用的东西。另外,对长度感到抱歉。我进行了相当多的编辑以生成我能想到的最小示例来重现该问题。
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
// Check if File exists
void FileExists(FILE *FilePath) {
if (FilePath == NULL) {
fprintf(stderr, "Error: File not found.\n");
exit(1);
}
}
// Delete a string_t struct
int delString(string_t *Structure)
{
if (Structure != NULL) {
free(Structure->string);
free(Structure);
return 0;
}
return 1;
}
// Allocate memory for additional elements added to members of list_t struct
void AllocList(list_t *List, size_t StrLen)
{
char **ArrStrArr_tmp;
size_t *SizeArr_tmp;
char *StrArr_tmp;
ArrStrArr_tmp = realloc(*List->arr, sizeof(**ArrStrArr_tmp) * List->recs);
SizeArr_tmp = realloc(List->arrSizes, sizeof(*SizeArr_tmp) * List->recs);
StrArr_tmp = malloc(sizeof(*StrArr_tmp) * StrLen);
if ((ArrStrArr_tmp == NULL) || (SizeArr_tmp == NULL)
|| (StrArr_tmp == NULL)) {
fprintf(stderr, "Failed to allocate memory.\n");
exit(1);
}
else {
List->arr = ArrStrArr_tmp;
List->arrSizes = SizeArr_tmp;
(List->arr)[List->recs-1]= StrArr_tmp;
}
}
// Add a record to a buffer
int AddRecord(list_t *List, char *AppendRecord)
{
string_t *line = NewString(AppendRecord);
List->recs++;
AllocList(List, line->size);
(List->arr)[List->recs - 1] = line->string;
(List->arrSizes)[List->recs - 1] = line->size;
delString(line);
return 0;
}
// Sends entire string array to lowercase
void tolowerString(char *UpperString, size_t StrLen)
{
int i;
for (i = 0; i < (int)StrLen; i++) {
UpperString[i] = (char)tolower(UpperString[i]);
}
}
// Attempt to match string in lines from a file; lines with matches are read into a buffer
int main()
{
char line[80];
int PrintedLines = 0;
list_t *ResultList = NewList();
char *MyString = "theme";
char *Filename = "List.txt";
FILE *in = fopen(Filename, "r");
// Check if file exists
FileExists(in);
while (fscanf(in, "%79[^\n]\n", line) == 1)
{
char LookString[80];
strcpy(LookString, line);
LookString[strlen(LookString) - 1] = '\0';
// send lookstring to lowercase
tolowerString(LookString, strlen(LookString));
// add line to buffer ResultList if it contains MyString
if (strstr(LookString, MyString)) {
AddRecord(ResultList, line);
PrintedLines++;
}
}
// If PrintedLines is at zero after the while statement terminates, return in abnormal state
if (PrintedLines == 0) {
fprintf(stderr, "No matches found. Please check your input if you are sure there is a match.\n");
return 1;
}
fclose(in);
return 0;
}
当尝试将第 5 条匹配记录读入我的缓冲区时,我的程序在 AllocList 函数的这一行崩溃:
ArrStrArr_tmp = realloc(*List->arr, sizeof(**ArrStrArr_tmp) * List->recs);
我在上面发布的版本中收到以下消息:
realloc(): invalid old size
aborted (core dumped)
我的猜测是,在使用了初始 malloc 中的一些默认内存量后,我遇到了错误,但我不知道究竟是什么原因造成的。在我的实际代码中,我正在打印各种东西(指针大小等),但我仍然无法发现任何东西。奇怪的是,在写这篇文章之前,我居然看到了错误:
realloc(): invalid next size
aborted (core dumped)
但由于某种原因我现在无法重现它......
我还读到,每当我将元素添加到其中一个成员时,我都应该为我的 list_t 结构重新分配内存,但重新分配它实际上并不会改变程序崩溃的位置或方式。无论如何,我不确定我应该如何为我的结构重新分配内存。为了澄清,我的问题是:
- 是什么导致了这个内存问题?
- 我应该为我的列表结构重新分配内存吗?考虑到我要向 arr 和 arrSizes 成员添加一个额外的元素,我应该重新分配多少内存?
【问题讨论】:
-
没有仔细阅读您的代码,重新分配
*List->arr并将其结果分配给List->arr看起来很不寻常。 -
在函数
AddRecord中,delString(line);被调用,line->string将在那里被释放,同时将值分配给(List->arr)[List->recs - 1]。这看起来很危险。 -
main函数中的line是什么? -
List->arr = malloc(sizeof(List->arr));和List->arrSizes = malloc(sizeof(List->arrSizes));看起来很奇怪,因为它们不是根据指向的大小而是根据指针的大小进行分配,但似乎没有害处,因为它们被认为有 0 个元素并且是重新分配的主题。 -
你应该检查
malloc()之后的List->arrSizes是否是NULL,而不是检查List->arr两次。