【问题标题】:Count elements of an unknown type array计算未知类型数组的元素
【发布时间】:2016-03-13 18:08:10
【问题描述】:

您好,我正在尝试编写一个函数,它返回作为参数传递的数组元素的数量,该函数必须适用于任何类型的数组

我试过这个:

int nb_elems(void* array)
{
    void* end = array;
    while(*end != NULL) // The last element have to be null, it is not counted.
        end++;

    return end - array;
}

如您所料,它不起作用。

事实上它甚至没有编译,我得到了这些错误:
错误:非法间接。
错误:void *:大小未知。
错误:void *:大小未知。

首先,你能告诉我我想做的事情是否可行?
其次,我试图实现这一目标的方式是否有意义,还是我完全没有抓住重点?
那么,为什么会出现这些错误,它们是什么意思?

感谢您的帮助!

【问题讨论】:

  • C 没有传递数组,nb_elems(void* array) 收到了一个指针。 void *pointer 不知道它指向多少个元素(也不知道类型)。
  • 我不确定你想做的事情是否可行。为了让您的函数计算数组中元素的数量,它必须有一种方法知道数组是什么类型,因为这是 C 编译器必须知道每个元素从哪里开始以及下一个元素在哪里结束的唯一方法。
  • 这是不可能的函数,但你可以使用宏,如果你确定你有一个数组而不仅仅是一个指针:stackoverflow.com/questions/37538/…
  • 我认为一种方法是使用引用机制调用,首先将数组的基地址存储在指针中并将其发送给函数,然后继续计数元素直到空字符在指针的帮助下访问必须计算长度的数组的值。

标签: c arrays types


【解决方案1】:

由于 C 不传递数组,nb_elems(void* array) 收到了一个指针void *pointer 不知道它指向多少个元素(也不知道类型)。

由于它需要“处理任何类型的数组”,因此代码需要定义如何将任意类型与NULL 进行比较。

您需要将指针、数组元素的大小和用于测试NULL 的函数传递给您的函数。

int nb_elems(void* array, size_t esize, int (*cmp)(void *ptr)) {
  char *ptr = array;
  int count = 0;
  while (*cmp(ptr) == 0) {
    ptr += esize;
    count++;
  }
  return count;
}

【讨论】:

  • 我什至没有意识到 NULL 只能分配给指针。
    但是对于我所看到的,如果与 NULL 的比较是用任何类型的指针进行的,它应该工作不是吗?
  • @aurelienC 是的,如果array 是指向指针数组的指针。比较测试只是*ptr == NULL。代码可以合理地假设所有指针大小相同并使用ptr++。迂腐的代码会传递指针的大小。但现在我们有一个新问题。
  • @aurelienC 详细信息:“NULL 只能分配给指针”不太正确。典型代码仅将 NULL 分配给指针。 intptr_t是整数类型,可以保存NULL,还有其他特殊情况,但最好只给指针赋值NULL
  • @aurelienC,可以不对,当成应该NULL 被设计为空指针常量。在某些平台上,它也可能被分配给整数类型,这只是一个工件。请确保对于整数类型,您始终使用0,这样您的意图就很明确,并且即使在您无法将NULL 分配给整数的平台上也能正常工作。
【解决方案2】:

因为您正在检查!= NULL 我想您有一个指针数组。使用指针数组,您的代码可以工作,因为您知道指针的大小,即使它是 void 指针。

如果我的假设是正确的,你可以这样编码:

int nb_elems(void** array) {
    void** end = array;
    while(*end != NULL) {
        end++;
    }
    return end - array;
}

但此代码仅适用于指向指针或指针数组的指针。


用法:

int** iptrs = (int**)malloc(3 * sizeof(int*));

iptrs[0] = (int*)malloc(sizeof(int));
*(iptrs[0]) = 42;
iptrs[1] = (int*)malloc(sizeof(int));
*(iptrs[1]) = 23;
iptrs[2] = NULL;

printf("%d", nb_elems(iptrs));

示例打印2

【讨论】:

  • 这很有趣,我要去调查看看我能用这个做什么。
  • 但是尝试Keep It Simple Stupid !!指向指针的指针可能非常棘手。
【解决方案3】:

不,你这样做的方式是不可能的,因为要进行指针运算(这里是 ++-),编译器必须知道数组的基本类型的大小。

另外void* 是指向void 的指针,即指向“非类型”。所以*end 的类型为void,你不能将它与任何东西进行比较,尤其是不能与NULL,它可能是指针类型或整数。如果您比较基类型为零,只需使用0

在开始尝试对任何类型的指针执行此操作之前,您应该对指向已知类型的指针尝试相同的操作,例如 unsigneddouble。如果您考虑到这一点来更改您的代码,它就有很好的工作机会。

【讨论】:

    【解决方案4】:

    您的代码无法编译的原因是编译器无法确定 void 的大小。以 ++ 运算符为例。我们可以大致翻译为:

    end = end + sizeof(void);
    

    void 的大小未定义,因此编译器无法为此生成任何代码,给您一个错误。

    接下来,您尝试取消引用 void 指针。这会给你一些类型为 void 的东西。但是由于 void 不代表任何东西(它什么都不代表),编译器无法判断这应该是什么。然后,您使用相等运算符将任何内容与 NULL 进行比较。您无法将任何内容与某事进行比较,因此这会产生错误。

    在 C 中,不可能实现一个函数来做这样的事情,仅仅是因为你无法判断 void* 的类型是什么。您至少需要知道传递给函数的类型以及将使用什么类型的特定值来终止数组。 C 不提供此功能,因此无法实现此类功能。

    【讨论】:

    • 看来我所做的主要问题是我将void*point 指向的内容而不是void*itself 与NULL 进行比较。
    • 如果您将参数(void*)与 NULL 进行比较,您将无法将任何数组传递给您的函数。比较总是会返回 false。
    【解决方案5】:

    如果你有一个实际的数组,而不是一个指针,你可以使用sizeof(array) / sizeof(array[0]) 来确定其中的元素数量。

    【讨论】:

    • 我在本网站的另一个问题上看到,此方法不适用于作为函数参数传递的数组。
    • 嗯,是的,无论如何您都不能将数组传递给函数(除非它嵌入在 structunion 中),但是由于 OP 想要一个函数,其唯一目的似乎是计算元素数组,由于这样的函数是不可能的,我的回答描述了如何确定实际数组中的元素数。
    猜你喜欢
    • 2013-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-18
    • 2021-10-10
    • 1970-01-01
    相关资源
    最近更新 更多