我有一个函数可以读取每行都包含一个单词的文本文件。这是我正在使用的文本文件的示例
and
but
five
follows
four
has
is
like
line
lines
littlest
not
once
one
only
other
six
the
three
twice
two
word
words
代码:
typedef struct node node_t;
struct node {
char data[MAX_WORD];
int term;
node_t *next;
};
node_t *head;
int
int_struct(int lines){
FILE *fp;
char ch;
int n = 0, i, switch_num=1, test_first=0, test_first_2=0;
node_t *node, *curr_add;
fp = fopen("text.txt", "r");
node = (node_t*)malloc(sizeof(node_t));
for (i=1; i<=lines; i++){
switch_num = 1;
n=0;
if (test_first != 0){
if (test_first_2){
node = (node_t*)malloc(1000000);
}
test_first_2=1;
while ((ch = getc(fp)) != '\n'){
node -> term = i;
node -> data[n] = ch;
n++;
}
curr_add -> next = node;
curr_add = node;
}
else{
test_first = 1;
head = curr_add = node;
}
}
curr_add -> next = NULL;
fclose(fp);
return num;
}
我想做的是读取每个单词并将其添加到链接列表中。
然而,我在使用 malloc 时遇到了麻烦(目前我只是添加了很多字节),并且需要有关如何在我拥有的函数中正确使用它的建议。我已经进行了一般搜索,并尽力尝试做大多数示例所做的事情。但我似乎仍然无法让我的功能发挥作用。例如,每次我执行该程序时,它都会读取所有单词并将其添加到链接列表中。但是,程序在最后一个单词处崩溃,并返回 NULL。如果有人能够指出我正确的方向,我将不胜感激。
最佳答案
问题
不检查返回值。特别是
fopen
和malloc
可能会返回NULL
。如果他们这样做,您将在 第一次尝试访问返回值。逻辑过于复杂。您不需要这些
switch_num
、test_first
和test_first_2
变量(请参阅下面的示例代码)。当您逐行读取文本文件时,不需要
getc
- 使用 改为fgets
。内存分配过多。每行不需要超过
sizeof(node_t)
+ 行长度 字节。分配的内存未释放。动态内存应该被释放为 不需要时尽快。
使用链表的示例
下面将文本文件读取到链接列表中。内存分配用于
每个列表项以及文件中的每一行都会占用 n * 2
内存
分配,其中 n
是文件中的行数。
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* strerror, strdup */
#include <errno.h>
typedef struct _node {
unsigned line;
char *data;
struct _node *next;
} node_t;
static void
destroy_list(node_t *list)
{
node_t *node;
for (node = list; node; node = node->next) {
if (node->data != NULL)
free(node->data);
free(node);
}
}
static node_t *
create_list_item(const char *data, unsigned line)
{
node_t *node = calloc(1, sizeof(node_t));
if (node == NULL) {
fprintf(stderr, "calloc: %s\n", strerror(errno));
} else {
node->line = line;
node->data = strdup(data);
if (node->data == NULL) {
fprintf(stderr, "strdup: %s\n", strerror(errno));
free(node);
node = NULL;
}
}
return node;
}
/* Returns pointer to new linked list */
static node_t *
read_file(FILE *fp, char *buf, size_t buf_len)
{
node_t *list = NULL;
node_t *prev = NULL;
node_t *node;
unsigned i;
for (i = 0; fgets(buf, buf_len, fp); prev = node) {
if ((node = create_list_item(buf, ++i)) == NULL) {
fprintf(stderr, "calloc: %s\n", strerror(errno));
break;
}
if (list == NULL)
list = node;
if (prev != NULL)
prev->next = node;
}
return list;
}
static void
print_list(const node_t *list)
{
const node_t *node;
for (node = list; node; node = node->next)
printf("%d: %s", node->line, node->data);
}
int main(int argc, char const* argv[])
{
const char *filename = "text.txt";
char buf[1024] = {0};
FILE *fp = NULL;
node_t *list = NULL;
if (NULL == (fp = fopen(filename, "r"))) {
fprintf(stderr, "failed to open file %s: %s\n",
filename, strerror(errno));
return 1;
}
list = read_file(fp, buf, sizeof(buf));
fclose(fp);
if (list) {
print_list(list);
destroy_list(list);
}
return 0;
}
使用动态数组的示例
为文件中的每一行(两次)分配内存是低效的,
不仅因为系统调用(malloc
、realloc
等)的成本很高,
还因为这些项目放置得不连续。访问连续的
内存区域通常速度更快。
在下面的代码中,链表被动态数组替换。我们 一次初始化 10 行内存。根据需要增加大小。
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* strerror, strdup */
#include <errno.h>
typedef struct _node {
size_t line;
char *data;
} node_t;
static void
destroy_array(node_t *array, size_t size)
{
size_t i;
node_t *item;
for (i = 0; i < size; i++) {
item = &array[i];
if (item->data)
free(item->data);
}
free(array);
}
static void
print_array(node_t *array, size_t size)
{
size_t i;
node_t *item;
for (i = 0; i < size; i++) {
item = &array[i];
if (item->data) {
printf("%ld: %s", item->line, item->data);
}
}
}
static node_t *
read_file(FILE *fp, char *buf, size_t buf_len,
const size_t array_step, size_t *array_size)
{
node_t *item;
node_t *array = calloc(array_step, sizeof(node_t));
size_t size = 0;
if (array == NULL) {
fprintf(stderr, "calloc:%s\n", strerror(errno));
return array;
}
while (fgets(buf, buf_len, fp)) {
if (size && size % array_step == 0) {
array = realloc(array, sizeof(node_t) * (array_step + size));
if (array == NULL) {
fprintf(stderr, "realloc:%s\n", strerror(errno));
break;
}
}
item = &array[size++];
item->line = size;
item->data = strdup(buf);
if (item->data == NULL) {
fprintf(stderr, "strdup: %s\n", strerror(errno));
break;
}
}
*array_size = size;
return array;
}
int main(int argc, char const* argv[])
{
node_t *array;
const size_t array_step = 10;
size_t array_size;
const char *filename = "text.txt";
char buf[1024] = {0};
FILE *fp = NULL;
if (NULL == (fp = fopen(filename, "r"))) {
fprintf(stderr, "failed to open file %s: %s\n",
filename, strerror(errno));
return 1;
}
array = read_file(fp, buf, sizeof(buf), array_step, &array_size);
fclose(fp);
if (array) {
print_array(array, array_size);
destroy_array(array, array_size);
}
return 0;
}
注意node_t
结构中的变化。
关于c - Malloc 和链表的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39990828/