问题
没有检查返回值。特别是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 结构的变化。