我得到了一个具有特定结构的.txt文件:每行都有一个 5 个字符但行数随机的字符串,我们应该读取文件并根据需要存储它。 我尝试过使用链表来做这件事,它工作得很好,但随着文件大小的增长,执行所需的时间太长了。从那时起,我一直在尝试将字符串存储到字符串数组中,因此所有内容都将连续存储在内存中。执行时,我收到分段错误错误,我不知道为什么。代码如下:
int nLines (char *path)
{
int answer = 0;
FILE* fp;
fp = fopen(path,"r");
char line[6];
while (fgets(line, sizeof(line),fp))
{
answer++;
}
return answer;
}
int main (int argc, char *argv[])
{
FILE* fp;
fp = fopen(argv[1], "r");
int numberLines = nLines(argv[1]);
char **storage = malloc(numberLines * 6 * sizeof(char));
if(storage != NULL)
{
int i = 0;
char line [6];
while (fgets(line, sizeof(line),fp))
{
strcpy(storage[i], line);
i++;
}
}
free(storage);
}
第一个函数应该返回文件中的行数。有了这些信息,我正在尝试分配等于字符串数量 * 每个字符串大小的内存,因为我事先知道这个值。我想象问题来自这行:
char **storage = malloc (numberLines * 6 *sizeof(char));
我已经很久没有碰过 C 了,我对整个指针和记忆的东西有点生疏。有人可以帮忙吗?谢谢!
您的分配是错误的
int main (int argc, char *argv[])
{
FILE* fp;
fp = fopen(argv[1], "r");
size_t numberLines = 0;
char **storage = NULL;
char line [8];
while (fgets(line, sizeof(line),fp))
{
storage = realloc(storage, (numberLines + 1) * sizeof(*storage));
storage[numberLines] = malloc(8);
strcpy(storage[numlines++], line);
}
/* ... */
}
您需要为指针分配空间,然后为字符串分配空间。它只是演示,您应该实现正确的错误处理(内存和文件(。
如果一个人想真正拥有一个在线算法,他就不会有可用的行数。拥有连续动态容器的惯用方法是重新分配几何增加的容量,如矢量或 ArrayList。C
没有内置该类型,但如果经常使用它,则值得额外的代码。例如,这从stdin
读取到EOF
,并使用斐波那契数列作为其容量。
#include <stddef.h>
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
/** One line of maximum 5 `char` plus 1 `NUL`. */
struct Line { char str[6]; };
/** A dynamic line array. */
struct LineArray {
struct Line *data; /* data -> (c0 < c1 || c0 == c1 == max_size) */
size_t capacity, next_capacity; /* !data -> !size, data -> size<=capacity */
size_t size;
};
/** Ensures `min_capacity` of `a`. Return success, otherwise, `errno` will be
set: `realloc` or `ERANGE` -- tried allocating more then can fit in `size_t`
or `realloc` doesn't follow [IEEE Std 1003.1-2001
](https://pubs.opengroup.org/onlinepubs/009695399/functions/realloc.html). */
static int reserve(struct LineArray *const a, const size_t min_capacity) {
size_t c0, c1;
struct Line *data;
const size_t max_size = (size_t)-1 / sizeof(struct Line *);
assert(a);
if(!a->data) {
if(!min_capacity) return 1;
c0 = 8, c1 = 13;
} else {
if(min_capacity <= a->capacity) return 1;
c0 = a->capacity, c1 = a->next_capacity;
}
if(min_capacity > max_size) return errno = ERANGE, 0;
assert(c0 < c1); /* Fibonacci: c0 ^= c1, c1 ^= c0, c0 ^= c1, c1 += c0. */
while(c0 < min_capacity) {
size_t temp = c0 + c1; c0 = c1; c1 = temp;
if(c1 > max_size || c1 < c0) c1 = max_size;
}
if(!(data = realloc(a->data, c0 * sizeof *a->data)))
{ if(!errno) errno = ERANGE; return 0; }
a->data = data;
a->capacity = c0;
a->next_capacity = c1;
return 1;
}
/** Adds one to the size of `a` and returns it (`push_back`.) Exceptional
return null and `errno` is `realloc` or `ERANGE`. */
static struct Line *new_line(struct LineArray *const a) {
assert(a);
if(a->size >= (size_t)-1) { errno = ERANGE; return 0; } /* Unlikely. */
if(!reserve(a, a->size + 1)) return 0; /* (Less) unlikely. */
return a->data + a->size++;
}
/** Destructor. */
static void linearray_(struct LineArray *const a) {
assert(a);
free(a->data);
a->data = 0, a->capacity = a->next_capacity = a->size = 0;
}
#include <string.h>
#include <stdio.h>
int main(void)
{
struct LineArray storage = { 0, 0, 0, 0 };
struct Line *s, *s_end;
size_t l = 0, line_len;
char line[7] = "";
int success = EXIT_FAILURE;
/* `line` must be capable of storing the "*[,5]n ". */
assert(sizeof line == sizeof ((struct Line *)0)->str + 1);
while (fgets(line, sizeof line, stdin))
{
l++;
line_len = strlen(line);
assert(line_len && line_len < sizeof line);
/* Too long. */
if(line[line_len - 1] != 'n') { errno = ERANGE; goto catch; }
/* Cut off the trailing new-line. */
line[line_len-- - 1] = ' ';
/* Store `line`. */
if(!(s = new_line(&storage))) goto catch;
strcpy(s->str, line);
}
if(ferror(stdin)) goto catch;
/* Print all. */
for(s = storage.data, s_end = s + storage.size; s < s_end; s++)
printf("stored: %sn", s->str);
success = EXIT_SUCCESS;
goto finally;
catch:
perror("Error");
fprintf(stderr, "On line %lu: "%s".n", (unsigned long)l, line);
finally:
linearray_(&storage);
return success;
}