考虑如下代码:
int i, a_size, s_size, n;
char **a;
a_size = 100; // examples
s_size = 10;
a = malloc(a_size * sizeof(char*));
for (int i = 0; i < a_size; i++)
a[i] = malloc((s_size) * sizeof(char));
现在,我想动态地计算数组中有多少元素(因此,忽略a_size
)。哪一种方法是正确的?
一般来说你不能,你应该自己处理这种簿记,但一种可能性是存储一个额外的行指针集到NULL
(又名哨兵):
a = malloc((a_size + 1) * sizeof(char*)); // allocate additional row pointer
for (int i = 0; i < a_size; i++) // allocate rows
a[i] = malloc(s_size);
a[a_size] = NULL; // set sentinel row to NULL
然后,您可以通过遍历行指针来确定大小,直到找到NULL
行。请注意,如果您经常这样做,或者如果行数可能很大,那么这可能会非常低效。
TL;DR指针不存储有关已分配内存大小的任何信息。因此,没有直接的API类型的东西,我们可以使用它来确定分配的大小。
然而,一些动态内存分配库提供了一些选项来实际获取有关已分配大小的信息,但这是非标准的,并且严重依赖于实现。
也就是说,您可以考虑一种方法,可以显式地标记数据的末尾(检查哨兵值概念)存储到动态分配的内存中(因此,本质上,标记分配的内存的末尾),但是,这也是您必须注意的事情。
请记住。正如Paul R先生非常正确地提到的那样,这种哨兵值方法可能非常低效,并且这种方法可能存在许多限制,例如
- 哨兵值不能作为合法值之一。
- 如果哨兵值没有出现在分配的最后,它可能会提供关于分配大小的错误信息。
- 你总是分配一些内存(放置哨兵),这些内存没有被有效地使用。
等等。
IMHO,最好的方法是,在一个单独的变量中跟踪分配的大小,并在必要时用指针传递它。
首先你动态地分配了101个一维数组
分配的字符总数等于产品s_size * s_size
。
您可以使用哨兵,但通常很难为哨兵选择一个值。
所以你应该自己把这些值存储在变量中。
你需要确定一个字符串的长度存储在一个一维数组的元素类型为char
,你应该使用标准的C函数strlen
声明在头<string.h>
。例如
strlen( a[0] )
实现所需簿记机制的一种可能性(尽管这可能不是一种好方法)是实现自定义分配,大小和自由函数,可以用以下方式勾画,其中size_t
是用于数组大小的类型;该方法类似于Pascal风格的字符串。
对于分配,分配更多的sizeof(t_size)
内存,将其写入分配块的开头,并返回一个指向第一个sizeof(t_size)
字节后的指针。
查看数组前的sizeof(t_size)
字节,即可获得数组的大小。
对于free函数,从存储大小的位置开始释放内存块,这是实际分配的块的开始。