【问题标题】:Array by reference length in C++ [duplicate]C ++中按引用长度排列的数组[重复]
【发布时间】:2011-06-30 17:14:51
【问题描述】:

可能重复: Calculating size of an array

这个问题以前有人问过,但我想确认一下。假设我有以下 C++ 函数:

#include <stdio.h>
#include <stdin.h>
#define length(a) sizeof(a)/sizeof(a[0])

int main()
{
    double c[] = {1.0, 2.0, 3.0};
    printf("%d\n", getLength(c));
    return 0;
}

int getLength(double c[]) { return length(c);}

这应该返回错误的值,因为 size of 将返回指针的大小,而不是指向的数组的大小。这个:

template<typename T, int size>
int length(T(&)[size]){return size;}

我知道它可以直接工作,但我想知道我是否可以以某种方式间接调用它,即通过辅助函数。我了解两种可能的选择是将数组的长度存储在单独的插槽中或使用向量,但我想知道的是:

给定一个函数getLength:

getLength(double arr[])
{
...
}

有没有办法在不传递更多信息的情况下计算arr 的长度?

【问题讨论】:

  • @AUpadhyay:我无法编译您的第二个示例。
  • 固定的第二个编译示例:codepad.org/0fSl8FKX
  • 你的第一个例子也有一个错误,在这里修复:codepad.org/6TctYm8p
  • 感谢 0A0D,但我的测试代码示例是为了不编译。 getLength 函数是多余的,但我想知道如果将数组作为参数传递给另一个函数,是否有任何方法可以获取数组的大小。
  • @AUpadhyay:这不是其他回答者所推断的。

标签: c++ arrays


【解决方案1】:

问题归结为编译时信息和运行时信息的区别。

模板有效,因为数组的大小在编译时是已知的,并且模板在编译时被评估。

另一个函数不起作用,因为在编译时只知道该函数将使用数组调用。函数原型中未指定数组的大小。也没有传递关于数组大小的运行时信息,除非您添加另一个参数并显式传递它。

【讨论】:

  • 那么我是否正确理解从 getLength() 调用 length() 时会因为执行 getLength() 时不知道数组的大小而失败?
  • @AUpadhyay:当然知道,数组c在编译时分配了4个元素。您在第一个示例中创建了一个宏。
  • 1.它分配了 3 个元素,而不是 4 个。我认为您可能在这里将数组与字符串混淆了。
  • 2.数组的大小被运行时“遗忘”。在以这种方式分配数组的情况下(即在堆栈上),数组元素在开始时被放在堆栈上,然后当函数返回时,堆栈帧被调整到函数调用开始时的位置。运行时不知道也不关心数组有多大。
  • @AUpadhyay:当编译器处理getLength() 时,它不知道您将传递哪些可能的参数,范围从int* 到任何大小的数组。标准规定编译器将类型为 array of size N of T 的参数转换为 pointer to T (这就是我不喜欢使用数组语法的原因在函数参数中:如果是指针,则称其为指针!)
【解决方案2】:

模板版本可以工作。谁说它不会起作用?

template<typename T, int size>
int length(T(&)[size])
{
   return size;
}

这是正确的。它将返回数组的长度。 你只需要直接调用这个函数就行了。 看来你是想从getLength()调用这个函数。不要那样做,因为你写的getLength函数的方式是等价的:

int getLength(double *c) { return length(c);}

你写的getLength()和上面的版本完全没有区别。也就是说,一旦你调用了这个函数,(或你的函数),数组已经衰减成一个 pointer 来加倍。随着数组的衰减,您已经丢失了size 信息(这就是为什么它被称为decaying of array)。所以你不应该调用这个函数,而是直接调用length()函数..

不过,length() 也没有什么问题。你不能在需要 const-expression 的地方使用这个函数,例如:

int anotherArray[length(c) * 10]; //error

所以解决办法是这样的:

template < std::size_t N >
struct value2type { typedef char type[N]; };

template < typename T, std::size_t size >
typename value2type<size>::type& sizeof_array_helper(T(&)[size]);

#define length(a) sizeof(sizeof_array_helper(a))

现在你可以写了:

int anotherArray[length(c) * 10]; //ok

【讨论】:

  • 模板可以工作,但它是从一个已经丢失数组维度的函数中调用的。
  • 我在模板版本不起作用的地方添加了我使用过的测试代码。我写错了吗?另外,我知道它可以直接工作,但我想知道我是否可以以某种方式间接调用它,即通过辅助函数。
  • @AUpadhyay:您不能从 getLength(..) 调用长度。那是你的问题。
  • @0A0D - 为什么?使用宏或模板版本,我想了解为什么我们不能从 getLength() 调用长度。
  • 这很有道理,谢谢。我不使用 C++(仅 C)编写代码,但我听说过“数组和指针是相同的,除非它们不是。”,我猜这是那些“不”之一!欣赏它
【解决方案3】:

要修复您的第一个示例,您必须执行以下操作(取自 answer 的长度宏):

#include <stdlib.h>
#include <stdio.h>

#define length(a) ((sizeof(a)/sizeof(0[a])) / ((size_t)(!(sizeof(a) % sizeof(0[a])))))

int main()
{
    double c[] = {1.0, 2.0, 3.0};
    printf("%d\n", length(c));
    return 0;
}

请注意,我没有从 getLength() 调用长度,因为这会导致除以零的问题。

您可以用#define length(a) (sizeof(a) / sizeof(*a)) 替换我的宏,但这将返回 1 作为大小,这是错误的。

您的第一个示例在修复后(请参阅我对您的回答的评论),将返回零大小。

您不能从 getLength() 函数调用模板化函数。

以下代码将修复您的模板示例:

#include <stdlib.h>
#include <stdio.h>
int getLength(double c[]);

template<typename T, int size>
int length(T(&)[size])
{
   return size;
}

int main()
{
    double c[] = {1.0, 2.0, 3.0, 4.0};
    printf("%d\n", length(c));

    return 0;
}

所以要回答您的问题,不,您必须采用上述两种方法之一。您不能像正在做的那样传递数组,因为数组会衰减为指针。这就是为什么首选通过引用传递的原因。通过引用将给出正确的 sizeof()。看到这个answer

【讨论】:

  • 非常感谢您的帮助 0A0D。我只有一个问题。当您说“不允许从 getLength() 函数调用模板化函数”时。为什么?这是一般规则吗?如果是这样,你知道我可以在哪里阅读更多关于它的信息吗?谢谢
  • @AUpadhyay:在我的答案和相关链接底部查看我的更新。
猜你喜欢
  • 2023-03-11
  • 2022-08-14
  • 1970-01-01
  • 2020-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-23
相关资源
最近更新 更多