如何计算数组的元素个数
How to count the number of elements of an array
我在测试code.I时遇到了一个问题定义一个获取数组元素数量的宏如下:
#define ARRAY_SIZE(arr) sizeof(arr) / sizeof(arr[0])
这个宏可以很好地计算初始值与存储容量相匹配的数组的元素数量(例如 int buf[] = {1,2,3};
),但对于声明为 int buf[20] = {1,2,3};
[=14 的数组则不是很有效=]
现在我知道像这样计算数组元素很容易,但是大量元素呢?你如何计算它们?数数可能是一个杀手,你知道的!
考虑以下代码:
#include <stdio.h>
#include <string.h>
#define ARRAY_SIZE(arr) sizeof(arr) / sizeof(arr[0])
void g_strcat(void *_Dst, size_t dstSize, size_t bytes, const void *_Src, size_t srcSize);
int main(void)
{
int dst[20] = { 1,2,3 };
int src[] = { 4,5,6 };
size_t dstSize = 3; // dstSize = ARRAY_SIZE(dst) doesn't work
size_t srcSize = ARRAY_SIZE(src);
g_strcat(dst, dstSize, sizeof(int), src, srcSize);
size_t n, newSize = dstSize + srcSize;
for (n = 0; n < newSize; n++) {
printf("%d ", dst[n]);
}
putchar('\n');
return 0;
}
void g_strcat(void *_Dst, size_t dstSize, size_t bytes, const void *_Src, size_t srcSize)
{
memcpy((char *)_Dst + (dstSize * bytes), _Src, srcSize * bytes);
}
您的宏运行良好。语句:
int dst[20] = { 1,2,3 };
在堆栈内存中创建以下内容:
|1|2|3|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|
即使只用前三个值初始化数组大小仍然是 20
关于评论中的问题:我将如何连接到数组?该数组必须足够大以容纳另一个字符串:
如果您使用的是字符串(而不是数字数组),则字符串函数 int len = strlen(string);
可用于在连接之前测试字符串变量的现有用法。
与sizeof
宏不同,strlen
是一个在字符数组中查找第一个NULL字符的函数:
char string[20] = {"yes"};
在内存中创建以下内容:
|y|e|s|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|
strlen
从string
的地址开始计算字符,直到遇到第一个NULL。 (或 0):
int len strlen(string); //will yield a len of 3
然后您可以使用 strncat(string, newStr, count);
将指定数量的字符 count 连接到已知容量的字符串,从而避免缓冲区溢出。
请记住,例如 size == 20 的字符串变量仅限于包含 length == 19 的字符串.第20位必须为NULL字符保留
如果我们可以假设最后一个初始化的元素不为零(因为这与隐式初始化为零没有区别),这将执行此操作:
size_t trailing_zero_bytes(const void* data, size_t size) {
for (; size > 0; size--) {
if (((const char*)data)[size - 1] != 0) {
break;
}
}
return size;
}
#define ARRAY_SIZE(arr) \
((sizeof(arr) - trailing_zero_bytes(arr, sizeof(arr)) + sizeof(arr[0]) + 1) / sizeof(arr[0]))
如果你想以不同的方式计算这两种情况,那你就完全不走运了(除非你使用 Clang 或 GCC-XML 或其他方式解析代码):
int s1[5] = { 4,5,6 }; // 2 zeros implied
int s2[5] = { 4,5,6,0 }; // 1 zero implied
以上两种方法都会3
我的方法,对此无能为力。
如果您仅部分初始化原始数据类型列表(即:int
的数组),则其余元素将初始化为 0
.
C99 Standard 6.7.8.21
If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, or fewer characters in
a string literal used to initialize an array of known size than there
are elements in the array, the remainder of the aggregate shall be
initialized implicitly the same as objects that have static storage
duration.
在您的例子中,您正在尝试确定初始值设定项列表的大小。真的想不出需要这样做的正当理由,但您可以简单地检查元素何时开始始终等于零。当然,如果你故意将一个元素设置为零,这会失败。
您编写的宏将正常工作(即:return 数组中的元素数),但如果您在接受数组指针作为参数的函数中使用它,它将失败参数,as pointer decay causes sizeof to act differently than one might expect.
综上所述,您无法确定任何有意义的初始化列表的大小,除非您这样做,将初始化列表定义为宏:
代码清单
#include <stdio.h>
#define LIST {1,2,3}
int main(void)
{
int i[20] = LIST;
int t[] = LIST;
printf("elements in i: %d\n", sizeof(i)/sizeof(int));
printf("elements in t: %d\n", sizeof(t)/sizeof(int));
return 0;
}
示例输出
elements in i: 20
elements in t: 3
您可以通过将丢弃的数组放入新的块作用域来最大程度地减少内存浪费,即:
#include <stdio.h>
#define LIST {1,2,3}
int main(void)
{
int i[20] = LIST;
int initListSize = 0;
{
int t[] = LIST;
initListSize = sizeof(t) / sizeof(int);
}
printf("elements in t: %d\n", initListSize);
return 0;
}
这会将临时数组的存储寿命限制在大括号之间的狭窄范围内。同样,我可以看到这可能作为一个实验很有用,但看不到它在生产代码中的应用。
如果要确定数组的初始值设定项的数量,请声明一个数组来保存初始值设定项元素并在 it.Then 上应用宏 ARRAY_SIZE()
使用 memcpy()
复制dst[20]
数组的初始值设定项。
现在你已经拥有了元素的数量。
#include <stdio.h>
#include <string.h>
#define ARRAY_SIZE(arr) sizeof(arr) / sizeof(arr[0])
void g_strcat(void *_Dst, size_t dstSize, size_t bytes, const void *_Src, size_t srcSize);
int main(void)
{
int dst[20], src[] = { 4,5,6 };
int initializer_list[] = { 1,2,3 };
size_t init_size = ARRAY_SIZE(initializer_list);
memcpy(dst, initializer_list, init_size * sizeof(int));
size_t dstSize = init_size;
size_t srcSize = ARRAY_SIZE(src);
g_strcat(dst, dstSize, sizeof(int), src, srcSize);
dstSize += srcSize;
size_t n;
for (n = 0; n < dstSize; n++) {
printf("%d ", dst[n]);
}
putchar('\n');
return 0;
}
void g_strcat(void *_Dst, size_t dstSize, size_t bytes, const void *_Src, size_t srcSize)
{
memcpy((char *)_Dst + (dstSize * bytes), _Src, srcSize * bytes);
}
我在测试code.I时遇到了一个问题定义一个获取数组元素数量的宏如下:
#define ARRAY_SIZE(arr) sizeof(arr) / sizeof(arr[0])
这个宏可以很好地计算初始值与存储容量相匹配的数组的元素数量(例如 int buf[] = {1,2,3};
),但对于声明为 int buf[20] = {1,2,3};
[=14 的数组则不是很有效=]
现在我知道像这样计算数组元素很容易,但是大量元素呢?你如何计算它们?数数可能是一个杀手,你知道的!
考虑以下代码:
#include <stdio.h>
#include <string.h>
#define ARRAY_SIZE(arr) sizeof(arr) / sizeof(arr[0])
void g_strcat(void *_Dst, size_t dstSize, size_t bytes, const void *_Src, size_t srcSize);
int main(void)
{
int dst[20] = { 1,2,3 };
int src[] = { 4,5,6 };
size_t dstSize = 3; // dstSize = ARRAY_SIZE(dst) doesn't work
size_t srcSize = ARRAY_SIZE(src);
g_strcat(dst, dstSize, sizeof(int), src, srcSize);
size_t n, newSize = dstSize + srcSize;
for (n = 0; n < newSize; n++) {
printf("%d ", dst[n]);
}
putchar('\n');
return 0;
}
void g_strcat(void *_Dst, size_t dstSize, size_t bytes, const void *_Src, size_t srcSize)
{
memcpy((char *)_Dst + (dstSize * bytes), _Src, srcSize * bytes);
}
您的宏运行良好。语句:
int dst[20] = { 1,2,3 };
在堆栈内存中创建以下内容:
|1|2|3|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|
即使只用前三个值初始化数组大小仍然是 20
关于评论中的问题:我将如何连接到数组?该数组必须足够大以容纳另一个字符串:
如果您使用的是字符串(而不是数字数组),则字符串函数 int len = strlen(string);
可用于在连接之前测试字符串变量的现有用法。
与sizeof
宏不同,strlen
是一个在字符数组中查找第一个NULL字符的函数:
char string[20] = {"yes"};
在内存中创建以下内容:
|y|e|s|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|
strlen
从string
的地址开始计算字符,直到遇到第一个NULL。 (或 0):
int len strlen(string); //will yield a len of 3
然后您可以使用 strncat(string, newStr, count);
将指定数量的字符 count 连接到已知容量的字符串,从而避免缓冲区溢出。
请记住,例如 size == 20 的字符串变量仅限于包含 length == 19 的字符串.第20位必须为NULL字符保留
如果我们可以假设最后一个初始化的元素不为零(因为这与隐式初始化为零没有区别),这将执行此操作:
size_t trailing_zero_bytes(const void* data, size_t size) {
for (; size > 0; size--) {
if (((const char*)data)[size - 1] != 0) {
break;
}
}
return size;
}
#define ARRAY_SIZE(arr) \
((sizeof(arr) - trailing_zero_bytes(arr, sizeof(arr)) + sizeof(arr[0]) + 1) / sizeof(arr[0]))
如果你想以不同的方式计算这两种情况,那你就完全不走运了(除非你使用 Clang 或 GCC-XML 或其他方式解析代码):
int s1[5] = { 4,5,6 }; // 2 zeros implied
int s2[5] = { 4,5,6,0 }; // 1 zero implied
以上两种方法都会3
我的方法,对此无能为力。
如果您仅部分初始化原始数据类型列表(即:int
的数组),则其余元素将初始化为 0
.
C99 Standard 6.7.8.21
If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, or fewer characters in a string literal used to initialize an array of known size than there are elements in the array, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration.
在您的例子中,您正在尝试确定初始值设定项列表的大小。真的想不出需要这样做的正当理由,但您可以简单地检查元素何时开始始终等于零。当然,如果你故意将一个元素设置为零,这会失败。
您编写的宏将正常工作(即:return 数组中的元素数),但如果您在接受数组指针作为参数的函数中使用它,它将失败参数,as pointer decay causes sizeof to act differently than one might expect.
综上所述,您无法确定任何有意义的初始化列表的大小,除非您这样做,将初始化列表定义为宏:
代码清单
#include <stdio.h>
#define LIST {1,2,3}
int main(void)
{
int i[20] = LIST;
int t[] = LIST;
printf("elements in i: %d\n", sizeof(i)/sizeof(int));
printf("elements in t: %d\n", sizeof(t)/sizeof(int));
return 0;
}
示例输出
elements in i: 20
elements in t: 3
您可以通过将丢弃的数组放入新的块作用域来最大程度地减少内存浪费,即:
#include <stdio.h>
#define LIST {1,2,3}
int main(void)
{
int i[20] = LIST;
int initListSize = 0;
{
int t[] = LIST;
initListSize = sizeof(t) / sizeof(int);
}
printf("elements in t: %d\n", initListSize);
return 0;
}
这会将临时数组的存储寿命限制在大括号之间的狭窄范围内。同样,我可以看到这可能作为一个实验很有用,但看不到它在生产代码中的应用。
如果要确定数组的初始值设定项的数量,请声明一个数组来保存初始值设定项元素并在 it.Then 上应用宏 ARRAY_SIZE()
使用 memcpy()
复制dst[20]
数组的初始值设定项。
现在你已经拥有了元素的数量。
#include <stdio.h>
#include <string.h>
#define ARRAY_SIZE(arr) sizeof(arr) / sizeof(arr[0])
void g_strcat(void *_Dst, size_t dstSize, size_t bytes, const void *_Src, size_t srcSize);
int main(void)
{
int dst[20], src[] = { 4,5,6 };
int initializer_list[] = { 1,2,3 };
size_t init_size = ARRAY_SIZE(initializer_list);
memcpy(dst, initializer_list, init_size * sizeof(int));
size_t dstSize = init_size;
size_t srcSize = ARRAY_SIZE(src);
g_strcat(dst, dstSize, sizeof(int), src, srcSize);
dstSize += srcSize;
size_t n;
for (n = 0; n < dstSize; n++) {
printf("%d ", dst[n]);
}
putchar('\n');
return 0;
}
void g_strcat(void *_Dst, size_t dstSize, size_t bytes, const void *_Src, size_t srcSize)
{
memcpy((char *)_Dst + (dstSize * bytes), _Src, srcSize * bytes);
}