除了所有其他很好的答案之外,为什么不使用 指向 int 2 数组的指针(或任何元素的大小)?在您的情况下,这是一种最佳方法。无需使用 指向 int 的指针。这使内存的分配和释放变得复杂。 指向数组的指针为您提供块的单次分配、所有已分配内存的单次释放和您想要的 2D 索引。
如果您从文件中读取并存储整数对的集合,则只需使用 指向数组的指针,例如
int (*arr)[2] = NULL;
这使得malloc 或calloc 的分配可以通过单个调用来分配存储初始数量的对,并通过单个调用来释放内存。例如,如果您有一个变量maxn 或64,那么要分配一块内存来保存从文件中读取的第一个64 整数对,您只需要:
arr = calloc (maxn, sizeof *arr);
无需单独调用为每个 2 整数分配存储空间,当您达到 64 的初始限制时,您只需 realloc 您的数组并继续前进。每次当前索引 idx 达到限制 maxn(新的内存块也归零)时,以下使用常量 MAXN 到 realloc 额外的 64 对:
if (++idx == maxn) {
printf ("\n reallocating %zu to %zu\n", maxn, maxn + MAXN);
size_t szelem = sizeof *arr;
void *tmp = realloc (arr, (maxn + MAXN) * szelem);
if (!tmp) {
fprintf (stderr, "realloc() error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
arr = tmp;
memset (arr + maxn * szelem, 0, MAXN * szelem);
maxn += MAXN;
}
为了方便起见,将所有部分放在一起并使用一些简单的错误检查功能,您可以执行类似于以下的操作:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* constants for number of columns, buffer chars, and initial allocation */
enum { NCOL = 2, MAXC = 32, MAXN = 64 };
void *xcalloc (size_t nmemb, size_t sz);
void *xrealloc (void *ptr, size_t psz, size_t *nelem);
FILE *xfopen (const char *fn, const char *mode);
int main (int argc, char **argv) {
char buf[MAXC] = {0};
char *fmt = "%d;%d";
int (*arr)[NCOL] = NULL;
size_t i, idx = 0, maxn = MAXN;
FILE *fp = argc > 1 ? xfopen (argv[1], "r") : stdin;
/* alloc mem for array of MAXN elements */
arr = xcalloc (maxn, sizeof *arr);
while (fgets (buf, MAXC, fp)) { /* read each line of input */
int a, b; /* parse line for values */
if (sscanf (buf, fmt, &a, &b) != NCOL) continue;
arr[idx][0] = a, arr[idx][1] = b;
if (++idx == maxn) /* realloc as needed */
arr = xrealloc (arr, sizeof *arr, &maxn);
}
if (fp != stdin) fclose (fp); /* close if not stdin */
for (i = 0; i < idx; i++)
printf (" array[%3zu][0] : %4d [1] : %d\n",
i, arr[i][0], arr[i][1]);
free (arr); /* free allocated memory */
return 0;
}
/** xcalloc allocates memory using calloc and validates the return. */
void *xcalloc (size_t nmemb, size_t sz)
{ register void *memptr = calloc (nmemb, sz);
if (!memptr) {
fprintf (stderr, "xcalloc() error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
return memptr;
}
/** realloc 'ptr' to array of elements of 'psz' to 'nelem + MAXN' elements */
void *xrealloc (void *ptr, size_t psz, size_t *nelem)
{ void *tmp = realloc ((char *)ptr, (*nelem + MAXN) * psz);
if (!tmp) {
fprintf (stderr, "realloc() error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
memset (tmp + *nelem * psz, 0, MAXN * psz); /* zero new memory */
*nelem += MAXN;
return tmp;
}
/** fopen with error checking - short version */
FILE *xfopen (const char *fn, const char *mode)
{ FILE *fp = fopen (fn, mode);
if (!fp) {
fprintf (stderr, "xfopen() error: file open failed '%s'.\n", fn);
// return NULL; /* choose appropriate action */
exit (EXIT_FAILURE);
}
return fp;
}
示例输入
对于64 对的初始分配,重新分配是强制读取整个文件。 (您可以在每次迭代时将初始大小设置为 1 和 realloc,但这非常低效 - MAXN 的初始大小必须至少为 1,并且应该设置为给定您的合理预期的元素数量数据)
$ cat dat/2d_data.txt
1;354
2;160
3;205
4;342
...
98;464
99;130
100;424
使用/输出示例
$ ./bin/array_ptr2array_realloc <dat/2d_data.txt
array[ 0][0] : 1 [1] : 354
array[ 1][0] : 2 [1] : 160
array[ 2][0] : 3 [1] : 205
array[ 3][0] : 4 [1] : 342
...
array[ 97][0] : 98 [1] : 464
array[ 98][0] : 99 [1] : 130
array[ 99][0] : 100 [1] : 424
内存使用/错误检查
在您编写的动态分配内存的任何代码中,对于分配的任何内存块,您都有 2 个责任:(1) 始终保留指向起始地址的指针内存块,因此,(2) 当不再需要它时可以释放。
您必须使用内存错误检查程序来确保您没有超出/超出分配的内存块,尝试读取或基于未初始化的值进行跳转,最后确认您已释放所有您分配的内存。对于 Linux,valgrind 是正常的选择。
$ valgrind ./bin/array_ptr2array_realloc <dat/2d_data.txt
==2796== Memcheck, a memory error detector
==2796== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==2796== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==2796== Command: ./bin/array_ptr2array_realloc
==2796==
array[ 0][0] : 1 [1] : 354
array[ 1][0] : 2 [1] : 160
array[ 2][0] : 3 [1] : 205
array[ 3][0] : 4 [1] : 342
...
array[ 97][0] : 98 [1] : 464
array[ 98][0] : 99 [1] : 130
array[ 99][0] : 100 [1] : 424
==2796==
==2796== HEAP SUMMARY:
==2796== in use at exit: 0 bytes in 0 blocks
==2796== total heap usage: 2 allocs, 2 frees, 1,536 bytes allocated
==2796==
==2796== All heap blocks were freed -- no leaks are possible
==2796==
==2796== For counts of detected and suppressed errors, rerun with: -v
==2796== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)
始终确认所有堆块都已释放——不可能有泄漏,同样重要的是错误摘要:0 个上下文中的 0 个错误。
查看所有答案,如果您还有其他问题,请告诉我。在诸如此类的许多情况下,使用指向数组的指针 非常有意义。它简化了内存的分配和释放,并保留了您的 2D 索引。