我正在尝试创建一个程序来读取文件并创建一个结构数组,并填充文件中的数据。问题是,当我运行这个时,我有时会得到一个调试断言失败!'错误表达式:_CtrlsValidHeapPointer(块),有时会出现问题,有时Visual Studio调试器会这样说: ConsoleApplication6.exe中0x775C1B45(ntdll.dll)的未处理异常:0xC0000005:访问冲突读取位置0x0040D510。
这是我的代码:
#include <stdio.h>
#define SIZE 256
struct Record {
char * firstName;
char * lastName;
char * address;
char * city;
char * state;
int * zipCode;
int * phoneNumber;
};
void initializeRecord(struct Record * list, char * lineOfText, int i);
void makeList(char * lineOfText, struct Record * list, int * psize);
int main(void) {
char lineOfText[SIZE];
int size = 0;
int * psize = &size;
struct Record * list = malloc(sizeof(struct Record));
makeList(lineOfText, list, psize);
free(list);
}
void makeList(char * lineOfText, struct Record * list, int * psize)
{
FILE * fp = fopen("myfile.txt", "r");
while (fgets(lineOfText, SIZE, fp)) {
list = realloc(list, sizeof(struct Record) + (*psize)*sizeof(struct Record));
initializeRecord(list, lineOfText, *psize);
(*psize)++;
}
fclose(fp);
}
void initializeRecord(struct Record * list, char * lineOfText, int i) {
char * newline = strchr(lineOfText, '\n');
if (newline)
*newline = 0;
char * firstName = strtok(lineOfText, "\t");
list[i].firstName = malloc(strlen(firstName)+1);
strcpy(list[i].firstName, firstName);
list[i].firstName[strlen(firstName) + 1] = '\0';
char *lastName = strtok(NULL, "\t");
list[i].lastName = malloc(strlen(lastName)+1);
strcpy(list[i].lastName, lastName);
list[i].lastName[strlen(lastName) + 1] = '\0';
char *address = strtok(NULL, "\t");
list[i].address = malloc(strlen(address)+1);
strcpy(list[i].address, address);
list[i].address[strlen(address) + 1] = '\0';
char *city = strtok(NULL, "\t");
list[i].city = malloc(strlen(city)+1);
strcpy(list[i].city, city);
list[i].city[strlen(address) + 1] = '\0';
char *state = strtok(NULL, "\t");
list[i].state = malloc(strlen(state)+1);
strcpy(list[i].state, state);
list[i].state[strlen(address) + 1] = '\0';
int *zipCode = strtok(NULL, "\t");
list[i].zipCode = malloc(strlen(zipCode)*sizeof(int)+1);
strcpy(list[i].zipCode, zipCode);
list[i].zipCode[strlen(zipCode)] = '\0';
int *phoneNumber = strtok(NULL, "\t");
list[i].phoneNumber = malloc(strlen(phoneNumber)*sizeof(int)+1);
strcpy(list[i].phoneNumber, phoneNumber);
list[i].phoneNumber[strlen(phoneNumber)] = '\0';
}
这是一个示例文件(除了之间不应该是全新的行,并且每个元素之间应该有标签,我只是看不到如何在StackOverflow上格式化它):
Mary Jones 6201 Wioewjife Ave DOHfeo Hills AZ 93321 2465551234
Billy Bob 7290 DIowhoefh St Uewopufeoi NY 23311 2345552393
John Jones 1234 EWOHFklfsh St WEDhofehif CA 98304 2345551238
Mark Joe 2398 Yeiofejp Blvd Hdeefoidjs MT 13210 4355553973
我的猜测是我的问题是,当我为数组分配空间时,我没有分配足够的空间,因为sizeof(struct Record)可能不足以存储我想要复制的内容,但是我和#39;我不确定如何创造足够的空间。
答案 0 :(得分:2)
您的代码中最大的错误是假设。你不能假设程序中的东西,特别是数据。使用strtok()
时,必须检查NULL
的返回值,这将表明找不到请求分隔符的令牌。
使用strtok()
也不是标记字符串的首选方法,因为它不是一个可重入的函数,在简单的情况下可以,但如果它变得像解析2个字符串一样复杂,那么它就不会工作。
使用malloc()
时始终确认分配成功。在一个简单的程序中,它不会引起大问题,但在数据敏感的程序中,您可能会破坏重要数据。这有很多原因,比如由于分段错误而丢失记录或写入损坏的数据,因为解除引用NULL
指针并不能保证分段错误 1 。你应该避免哪些。在无法关闭Web服务器的程序中,您必须确保检查所有内容是否存在错误。所以作为一个好习惯总是检查错误。
您的代码也是违反DRY Principle的一个很好的例子,尝试清理它以便错误发生在一个位置然后它们将影响程序到处,但您只需要在一个地方修复它们。
还有一件事,因为* alloc()
函数在失败时返回NULL
,
list = realloc(list, ...);
可能会出现问题,因为您会在list
之前覆盖NULL
,并且在调用realloc()
之前也无法访问它指向的数据。始终使用辅助变量realloc()
,测试成功,然后覆盖旧指针。
尽管* alloc()
函数失败是不太可能的,但这并非不可能,强大的程序应该认为它可以发生,因为它确实发生了。
1 这几乎肯定会发生,但根据标准,它应该是未定义的行为,所以无论如何都不能保证给定的行为
答案 1 :(得分:-1)
您告诉initializeRecord()
您正在发送单个记录,然后您尝试将其作为记录数组访问。这就是导致您访问违规行为的原因。