我有一个函数,读取每行填充一个单词的文本文件。下面是一个文本文件的例子,我使用
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: %sn", strerror(errno));
} else {
node->line = line;
node->data = strdup(data);
if (node->data == NULL) {
fprintf(stderr, "strdup: %sn", 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: %sn", 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: %sn",
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:%sn", 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:%sn", strerror(errno));
break;
}
}
item = &array[size++];
item->line = size;
item->data = strdup(buf);
if (item->data == NULL) {
fprintf(stderr, "strdup: %sn", 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: %sn",
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
结构的变化