为您的数据动态分配空间是使用 C 语言工作的基本工具。您不妨付出代价来学习。首先要记住的是,
"如果你分配内存,你有责任跟踪它的使用
并保留一个指向块的起始地址的指针
内存,这样你就可以在完成后释放它。否则你的
像筛子一样泄漏内存的代码。”
动态分配是直截了当的。您分配一些初始内存块并跟踪您添加的内容。您必须测试每个分配是否成功。您必须测试您使用了多少内存块,并在已满时重新分配或停止写入数据,以防止写入超出内存块的末尾。如果你没有测试任何一个,你将破坏与你的代码相关的内存。
重新分配时,请始终使用临时指针重新分配,因为重新分配失败时,原始内存块被释放。 (导致该块中所有先前数据的丢失)。使用临时指针可以让您在需要时以保留该块的方式处理故障。
考虑到这一点,下面我们最初为 64 个long 值分配空间(您可以轻松更改为处理任何类型的代码,例如int、float、double...)。然后代码读取每一行数据(使用getline 为每一行动态分配缓冲区)。 strtol 用于解析将值分配给array 的缓冲区。 idx 用作跟踪已读取的值的索引,当idx 达到当前的nmax 时,array 重新分配为以前的两倍,nmax 更新为反映变化。对文件中的每一行数据继续进行读取、解析、检查和重新分配。完成后,这些值将打印到标准输出,显示从格式化为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] : %ld\n", 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 %lu\n", *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 found\n");
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)