为什么读取文件功能崩溃?
Why is reading from file function crashing?
试图从文件中读取多行以将它们存储在由字符串元素组成的结构中,但是当我 运行 程序崩溃时我完全不知道为什么。
有问题的函数:
Hashtbl* loadfromfile(Hashtbl* hashtbl, char *path){
int i = 0;
char line[100];
char* string[40];
FILE *f = fopen(path, "r");
if(f == NULL){
printf("FILE NO FOUND!");
}else{
while(fgets(line, sizeof(line), f)!=NULL){
strcpy(string[i],line);
i++;
}
fclose(f);
for(i = 0; i<(SIZE*2); i++){
strcpy(hashtbl[i].subscript, string[i]);
i++;
}
for(i = 1; i<(SIZE*2); i++){
strcpy(hashtbl[i].value, string[i]);
i++;
}
return hashtbl;
}
}
main.c:
#include <stdio.h>
#include <stdlib.h>
#include "hashtable.h"
int main() {
Hashtbl* numbers;
numbers = init_hashtbl(); //init_hashtable initialises numbers
loadfromfile(numbers, "test.txt");
for(int i = 0; i<SIZE; i++) {
printf("%s1", numbers[i].subscript);
printf("%s2\n", numbers[i].value);
}
}
哈希表结构:
typedef struct Hashtbls{
char *subscript;
char *value;
} Hashtbl;
init_hasthable函数:
Hashtbl* init_hashtbl(){
Hashtbl* hashtbl;
hashtbl = calloc(SIZE, sizeof(Hashtbl));
for(int i = 0; i<SIZE; i++){
hashtbl[i].subscript = "ZERO";
hashtbl[i].value = "ZERO";
}
return hashtbl;
}
你这里有不少问题:
if(f == NULL){
printf("FILE NO FOUND!");
}
如果无法打开文件,则无法继续。消息也可能
稍后打印,请改用 printf("FILE NOT FOUND!\n");
。
char* string[40];
...
while(fgets(line, sizeof(line), f)!=NULL){
strcpy(string[i],line);
i++;
}
string
是一个未初始化的指针数组,不能写任何东西
那里。你应该做
while(fgets(line, sizeof line, f))
{
string[i] = malloc(strlen(line) + 1);
if(string[i] == NULL)
{
// error handling is needed
}
strcpy(string[i], line);
i++;
if(i == sizeof string / sizeof *string)
break;
}
// or if your system has strdup
while(fgets(line, sizeof line, f))
{
string[i] = strdup(line);
if(string[i] == NULL)
{
// error handling is needed
}
i++;
if(i == sizeof string / sizeof *string)
break;
}
你也没有检查你是否阅读了超过40行。我这样做了
最后一个if
。 sizeof array / sizeof *array
returns个数
数组可以容纳的元素。请注意,这仅适用于数组,不适用于
指针,因为通常 sizeof array != sizeof pointer
。也不要忘记
之后释放分配的内存。
strcpy(hashtbl[i].subscript, string[i]);
...
strcpy(hashtbl[i].value, string[i]);
此处的subscript
和value
参数是否以某种方式初始化?查看
你的 init_hashtbl()
.
编辑
现在您发布了 init_hashtbl
:
for(i = 0; i<(SIZE*2); i++){
strcpy(hashtbl[i].subscript, string[i]);
i++;
}
您正在使用字符串文字初始化 subscript
和 value
,它们
指向只读内存位置,strcpy
将失败。你有
使用 malloc
分配内存或使用数组更改结构。
选项 1
保持结构,改变init_hashtbl
Hashtbl* init_hashtbl(){
Hashtbl* hashtbl;
hashtbl = calloc(SIZE, sizeof(Hashtbl));
for(int i = 0; i<SIZE; i++){
hashtbl[i].subscript = malloc(SOME_MAXIMAL_LENGTH + 1);
strcpy(hashtbl[i].subscript, "ZERO");
hashtbl[i].value = malloc(SOME_MAXIMAL_LENGTH + 1);
strcpy(hashtbl[i].value, "ZERO");
}
return hashtbl;
}
您应该始终检查 malloc
/calloc
的 return 值。还有
这里的问题是,如果你想复制一个长于
SOME_MAXIMAL_LENGTH
,你会发生缓冲区溢出。所以你应该
在读取例程中使用 realloc:
for(i = 0; i<(SIZE*2); i++){
char *tmp = realloc(hashtbl[i].subscript, strlen(string[i]) + 1);
if(tmp == NULL)
{
// error handling
}
hashtbl[i].subscript = tmp;
strcpy(hashtbl[i].subscript, string[i]);
i++;
}
如果你不想在这里处理 realloc
,你必须确定,没有
string[i]
比 SOME_MAXIMAL_LENGTH
长。
选项 2
改变你的结构和初始化:
typedef struct Hashtbls{
char subscript[SOME_MAXIMAL_LENGTH];
char value[SOME_MAXIMAL_LENGTH];
} Hashtbl;
Hashtbl* init_hashtbl(){
Hashtbl* hashtbl;
hashtbl = calloc(SIZE, sizeof(Hashtbl));
for(int i = 0; i<SIZE; i++){
strcpy(hashtbl[i].subscript, "ZERO");
strcpy(hashtbl[i].value, "ZERO");
}
return hashtbl;
}
然后在loadfromfile
中你不必处理如图所示的realloc
以上,你可以保留你的代码。但是,您必须检查没有 string[i]
长于SOME_MAXIMAL_LENGTH - 1
,否则缓冲区溢出。
最后一件事,fgets
读取整行,假设
line 小于 sizeof line
,换行符将被添加到
线。您很可能不想拥有它。摆脱的一种方法
换行符是:
fgets(line, sizeof line, f);
int len = strlen(line);
if(line[len - 1] == '\n')
line[len - 1] = 0;
试图从文件中读取多行以将它们存储在由字符串元素组成的结构中,但是当我 运行 程序崩溃时我完全不知道为什么。
有问题的函数:
Hashtbl* loadfromfile(Hashtbl* hashtbl, char *path){
int i = 0;
char line[100];
char* string[40];
FILE *f = fopen(path, "r");
if(f == NULL){
printf("FILE NO FOUND!");
}else{
while(fgets(line, sizeof(line), f)!=NULL){
strcpy(string[i],line);
i++;
}
fclose(f);
for(i = 0; i<(SIZE*2); i++){
strcpy(hashtbl[i].subscript, string[i]);
i++;
}
for(i = 1; i<(SIZE*2); i++){
strcpy(hashtbl[i].value, string[i]);
i++;
}
return hashtbl;
}
}
main.c:
#include <stdio.h>
#include <stdlib.h>
#include "hashtable.h"
int main() {
Hashtbl* numbers;
numbers = init_hashtbl(); //init_hashtable initialises numbers
loadfromfile(numbers, "test.txt");
for(int i = 0; i<SIZE; i++) {
printf("%s1", numbers[i].subscript);
printf("%s2\n", numbers[i].value);
}
}
哈希表结构:
typedef struct Hashtbls{
char *subscript;
char *value;
} Hashtbl;
init_hasthable函数:
Hashtbl* init_hashtbl(){
Hashtbl* hashtbl;
hashtbl = calloc(SIZE, sizeof(Hashtbl));
for(int i = 0; i<SIZE; i++){
hashtbl[i].subscript = "ZERO";
hashtbl[i].value = "ZERO";
}
return hashtbl;
}
你这里有不少问题:
if(f == NULL){
printf("FILE NO FOUND!");
}
如果无法打开文件,则无法继续。消息也可能
稍后打印,请改用 printf("FILE NOT FOUND!\n");
。
char* string[40];
...
while(fgets(line, sizeof(line), f)!=NULL){
strcpy(string[i],line);
i++;
}
string
是一个未初始化的指针数组,不能写任何东西
那里。你应该做
while(fgets(line, sizeof line, f))
{
string[i] = malloc(strlen(line) + 1);
if(string[i] == NULL)
{
// error handling is needed
}
strcpy(string[i], line);
i++;
if(i == sizeof string / sizeof *string)
break;
}
// or if your system has strdup
while(fgets(line, sizeof line, f))
{
string[i] = strdup(line);
if(string[i] == NULL)
{
// error handling is needed
}
i++;
if(i == sizeof string / sizeof *string)
break;
}
你也没有检查你是否阅读了超过40行。我这样做了
最后一个if
。 sizeof array / sizeof *array
returns个数
数组可以容纳的元素。请注意,这仅适用于数组,不适用于
指针,因为通常 sizeof array != sizeof pointer
。也不要忘记
之后释放分配的内存。
strcpy(hashtbl[i].subscript, string[i]);
...
strcpy(hashtbl[i].value, string[i]);
此处的subscript
和value
参数是否以某种方式初始化?查看
你的 init_hashtbl()
.
编辑
现在您发布了 init_hashtbl
:
for(i = 0; i<(SIZE*2); i++){
strcpy(hashtbl[i].subscript, string[i]);
i++;
}
您正在使用字符串文字初始化 subscript
和 value
,它们
指向只读内存位置,strcpy
将失败。你有
使用 malloc
分配内存或使用数组更改结构。
选项 1
保持结构,改变init_hashtbl
Hashtbl* init_hashtbl(){
Hashtbl* hashtbl;
hashtbl = calloc(SIZE, sizeof(Hashtbl));
for(int i = 0; i<SIZE; i++){
hashtbl[i].subscript = malloc(SOME_MAXIMAL_LENGTH + 1);
strcpy(hashtbl[i].subscript, "ZERO");
hashtbl[i].value = malloc(SOME_MAXIMAL_LENGTH + 1);
strcpy(hashtbl[i].value, "ZERO");
}
return hashtbl;
}
您应该始终检查 malloc
/calloc
的 return 值。还有
这里的问题是,如果你想复制一个长于
SOME_MAXIMAL_LENGTH
,你会发生缓冲区溢出。所以你应该
在读取例程中使用 realloc:
for(i = 0; i<(SIZE*2); i++){
char *tmp = realloc(hashtbl[i].subscript, strlen(string[i]) + 1);
if(tmp == NULL)
{
// error handling
}
hashtbl[i].subscript = tmp;
strcpy(hashtbl[i].subscript, string[i]);
i++;
}
如果你不想在这里处理 realloc
,你必须确定,没有
string[i]
比 SOME_MAXIMAL_LENGTH
长。
选项 2
改变你的结构和初始化:
typedef struct Hashtbls{
char subscript[SOME_MAXIMAL_LENGTH];
char value[SOME_MAXIMAL_LENGTH];
} Hashtbl;
Hashtbl* init_hashtbl(){
Hashtbl* hashtbl;
hashtbl = calloc(SIZE, sizeof(Hashtbl));
for(int i = 0; i<SIZE; i++){
strcpy(hashtbl[i].subscript, "ZERO");
strcpy(hashtbl[i].value, "ZERO");
}
return hashtbl;
}
然后在loadfromfile
中你不必处理如图所示的realloc
以上,你可以保留你的代码。但是,您必须检查没有 string[i]
长于SOME_MAXIMAL_LENGTH - 1
,否则缓冲区溢出。
最后一件事,fgets
读取整行,假设
line 小于 sizeof line
,换行符将被添加到
线。您很可能不想拥有它。摆脱的一种方法
换行符是:
fgets(line, sizeof line, f);
int len = strlen(line);
if(line[len - 1] == '\n')
line[len - 1] = 0;