如何计算数组的元素数量

时间:2016-05-05 13:13:52

标签: c arrays counting

我在测试代码时遇到了问题。我定义了一个宏来获取数组元素的数量,如下所示:

#define ARRAY_SIZE(arr) sizeof(arr) / sizeof(arr[0])

此宏可用于计算初始化程序与存储容量匹配的数组的元素数(例如int buf[] = {1,2,3};),但对于声明为:int buf[20] = {1,2,3};的数组不是很有效

现在我知道像这样计算数组元素非常简单,但是大量的元素呢?你怎么算他们?你知道,计数可能是一个杀手!

请考虑以下代码:

#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);
}

4 个答案:

答案 0 :(得分:5)

如果您只部分初始化原始数据类型列表(即:int s的数组),则其余元素将初始化为0

  

C99标准6.7.8.21

     

如果括号括起的列表中的初始值设定项少于聚合的元素或成员,或者更少的字符   用于初始化已知大小的数组的字符串文字   是数组中的元素,聚合的其余部分应为   隐式初始化与具有静态存储的对象相同   持续时间。

在您的情况下,您正在尝试确定初始化列表的大小。无法真正想到需要这样做的正当理由,但您可以简单地检查元素何时始终等于零。当然,如果您故意将元素设置为零,则会失败。

您编写的宏将正常工作(即:返回数组中元素的数量),但如果您在接受指向数组的指针作为参数的函数中使用它,它将失败,{{3} }

所有这一切,你无法在任何有意义的意义上确定初始化列表的大小,除非你这样做,你将初始化列表定义为宏:

代码清单

#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;
}

这会将临时数组的存储生命周期限制为大括号之间的较窄范围。同样,我可以看到这可能作为一个实验很有用,但是无法看到它在生产代码中找到它的方式。

答案 1 :(得分:1)

你的宏工作正常。声明:

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|

strlenstring的地址开始,计算字符直到遇到第一个NULL。 (或0):

int len strlen(string); //will yield a len of 3

然后,您可以使用strncat(string, newStr, count);将指定数量的字符 count 连接到已知容量的字符串,从而避免缓冲区溢出。

请记住, size == 20的字符串变量仅限于包含 length == 19的字符串。必须保留第20个位置NULL字符。

答案 2 :(得分:1)

如果我们可以假设最后一个初始化元素不为零(因为它与隐式初始化为零无法区分),这将会这样做:

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的方法,而且没有什么可以做的。

答案 3 :(得分:0)

如果要确定数组的初始值设定项数,请声明一个数组以保存初始值设定项元素并在其上应用宏ARRAY_SIZE()。然后使用memcpy()将初始值设定项复制到{ {1}}数组。

现在您可以轻松获得元素数量。

dst[20]