我有一个文本文件,其中可能包含一个或最多400个数字。每个数字用逗号分隔,分号用于表示数字流的末尾。目前,我正在使用fgets逐行读取文本文件。出于这个原因,我使用了1024个元素的固定数组(文本文件每行的最大字符数)。这不是实现这一点的理想方式,因为如果在文本文件中只输入一个数字,那么1024个元素的数组将毫无意义。有没有一种方法可以将fgets与malloc函数一起使用(或任何其他方法)来提高内存效率?
如果您想在生产代码中使用它,我会要求您遵循注释部分中的建议
但是如果您的要求更多是为了学习或上学,那么这里有一种复杂的方法。
伪代码
1. Find the size of the file in bytes, you can use "stat" for this.
2. Since the file format is known, from the file size, calculate the number of items.
3. Use the number of items to malloc.
哇!:p
如何查找文件大小
您可以使用stat
,如下所示:
#include <sys/stat.h>
#include <stdio.h>
int main(void)
{
struct stat st;
if (stat("file", &st) == 0) {
printf("fileSize: %d No. of Items: %dn", (st.st_size), (st.st_size/2));
return st.st_size;
}
printf("failed!n");
return 0;
}
此文件在运行时将返回文件大小:
$> cat file
1;
$> ./a.out
fileSize: 3 No. of Items: 1
$> cat file
1,2,3;
$> ./a.out
fileSize: 7 No. of Items: 3
免责声明:这种最小化预分配内存的方法是最佳方法吗?天堂无路!:)
为您动态分配空间数据是在C中工作的基本工具。您不妨付出学习的代价。首先要记住的是,
"如果分配内存,则有责任跟踪其使用情况并保留指向的块的起始地址的指针内存,这样你就可以在用完后释放它。否则像筛子一样泄漏内存的代码。">
动态分配是直接的。您分配一些初始内存块,并跟踪添加的内容。您必须测试每次分配是否成功。您必须测试您使用的内存块的大小,并在已满时重新分配或停止写入数据,以防止写入超出内存块的末尾。如果测试失败,将损坏与代码相关的内存。
重新分配时,请始终使用临时指针进行重新分配,因为如果重新分配失败,则会释放原始内存块。(导致该块中所有以前的数据丢失)。使用临时指针可以在需要时以保留该块的方式处理故障。
考虑到这一点,下面我们首先为64个long
值分配空间(您可以很容易地更改为代码来处理任何类型,例如int
、float
、double
…)。然后代码读取每行数据(使用getline
为每行动态分配缓冲区)。CCD_ 7用于解析为CCD_。idx
被用作跟踪已经读取了多少值的索引,并且当idx
达到当前nmax
时,array
被重新分配为其先前的两倍大,并且nmax
被更新以反映该变化。继续对文件中的每一行数据进行读取、解析、检查和重新分配。完成后,将值打印到stdout,显示从格式化为353,394,257,...293,58,135;
的测试文件中读取的400个随机值
为了保持读取循环逻辑的整洁,我已经将strtol
转换的错误检查放入函数xstrtol
中,但如果您愿意,可以将该代码包含在main()
中。这同样适用于realloc_long
函数。要查看重新分配何时发生,可以使用-DDEBUG
定义编译代码。例如:
gcc -Wall -Wextra -DDEBUG -o progname yoursourcefile.c
程序希望您的数据文件名作为第一个参数,您可以提供一个可选的转换基作为第二个参数(默认值为10)。例如:
./progname datafile.txt [base (default: 10)]
看一遍,测试一下,如果你有任何问题,请告诉我。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#define NMAX 64
long xstrtol (char *p, char **ep, int base);
long *realloc_long (long *lp, unsigned long *n);
int main (int argc, char **argv)
{
char *ln = NULL; /* NULL forces getline to allocate */
size_t n = 0; /* max chars to read (0 - no limit) */
ssize_t nchr = 0; /* number of chars actually read */
size_t idx = 0; /* array index counter */
long *array = NULL; /* pointer to long */
unsigned long nmax = NMAX; /* initial reallocation counter */
FILE *fp = NULL; /* input file pointer */
int base = argc > 2 ? atoi (argv[2]) : 10; /* base (default: 10) */
/* open / validate file */
if (!(fp = fopen (argv[1], "r"))) {
fprintf (stderr, "error: file open failed '%s'.", argv[1]);
return 1;
}
/* allocate array of NMAX long using calloc to initialize to 0 */
if (!(array = calloc (NMAX, sizeof *array))) {
fprintf (stderr, "error: memory allocation failed.");
return 1;
}
/* read each line from file - separate into array */
while ((nchr = getline (&ln, &n, fp)) != -1)
{
char *p = ln; /* pointer to ln read by getline */
char *ep = NULL; /* endpointer for strtol */
while (errno == 0)
{ /* parse/convert each number in line into array */
array[idx++] = xstrtol (p, &ep, base);
if (idx == nmax) /* check NMAX / realloc */
array = realloc_long (array, &nmax);
/* skip delimiters/move pointer to next digit */
while (*ep && *ep != '-' && (*ep < '0' || *ep > '9')) ep++;
if (*ep)
p = ep;
else
break;
}
}
if (ln) free (ln); /* free memory allocated by getline */
if (fp) fclose (fp); /* close open file descriptor */
int i = 0;
for (i = 0; i < idx; i++)
printf (" array[%d] : %ldn", i, array[i]);
free (array);
return 0;
}
/* reallocate long pointer memory */
long *realloc_long (long *lp, unsigned long *n)
{
long *tmp = realloc (lp, 2 * *n * sizeof *lp);
#ifdef DEBUG
printf ("n reallocating %lu to %lun", *n, *n * 2);
#endif
if (!tmp) {
fprintf (stderr, "%s() error: reallocation failed.n", __func__);
// return NULL;
exit (EXIT_FAILURE);
}
lp = tmp;
memset (lp + *n, 0, *n * sizeof *lp); /* memset new ptrs 0 */
*n *= 2;
return lp;
}
long xstrtol (char *p, char **ep, int base)
{
errno = 0;
long tmp = strtol (p, ep, base);
/* Check for various possible errors */
if ((errno == ERANGE && (tmp == LONG_MIN || tmp == LONG_MAX)) ||
(errno != 0 && tmp == 0)) {
perror ("strtol");
exit (EXIT_FAILURE);
}
if (*ep == p) {
fprintf (stderr, "No digits were foundn");
exit (EXIT_FAILURE);
}
return tmp;
}
样本输出(带有-DDEBUG以显示重新分配)
$ ./bin/read_long_csv dat/randlong.txt
reallocating 64 to 128
reallocating 128 to 256
reallocating 256 to 512
array[0] : 353
array[1] : 394
array[2] : 257
array[3] : 173
array[4] : 389
array[5] : 332
array[6] : 338
array[7] : 293
array[8] : 58
array[9] : 135
<snip>
array[395] : 146
array[396] : 324
array[397] : 424
array[398] : 365
array[399] : 205
内存错误检查
$ valgrind ./bin/read_long_csv dat/randlong.txt
==26142== Memcheck, a memory error detector
==26142== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==26142== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==26142== Command: ./bin/read_long_csv dat/randlong.txt
==26142==
reallocating 64 to 128
reallocating 128 to 256
reallocating 256 to 512
array[0] : 353
array[1] : 394
array[2] : 257
array[3] : 173
array[4] : 389
array[5] : 332
array[6] : 338
array[7] : 293
array[8] : 58
array[9] : 135
<snip>
array[395] : 146
array[396] : 324
array[397] : 424
array[398] : 365
array[399] : 205
==26142==
==26142== HEAP SUMMARY:
==26142== in use at exit: 0 bytes in 0 blocks
==26142== total heap usage: 7 allocs, 7 frees, 9,886 bytes allocated
==26142==
==26142== All heap blocks were freed -- no leaks are possible
==26142==
==26142== For counts of detected and suppressed errors, rerun with: -v
==26142== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)