我可以在不必硬编码的情况下用C++确定数组的大小/长度吗
Can I determine the size/length of an array in C++ without having to hardcode it?
我基本上是在寻找某种将数组的大小/长度传递给函数的"动态"方式。
我试过:
void printArray(int arrayName[])
{
for(int i = 0 ; i < sizeof(arrayName); ++i)
{
cout << arrayName[i] << ' ';
}
}
但我意识到它只考虑字节大小,而不考虑数组中有多少元素。
还有:
void printArray(int *arrayName)
{
while (*arrayName)
{
cout << *arrayName << ' ';
*arrayName++;
}
}
这至少打印了我所有的东西,但比我预期的要多,所以它实际上并没有按照我想要的方式工作。我想这是因为我没有确切地告诉它我需要它有多大,所以它"安全"地向我抛出一些大的大小,并最终在数组中的最后一个元素之后开始打印非常奇怪的整数。
所以我终于完成了这项工作,但我相信还有更好的东西!:
void printArray(int *arrayName)
{
while (*arrayName)
{
if (*arrayName == -858993460)
{
break;
}
cout << *arrayName << ' ';
*arrayName++;
}
cout << 'n';
}
在运行了几次程序后,我意识到我输入的数组的最后一个元素之后的值总是:-858993460,所以一旦遇到这个值,我就让它中断while循环。
include <iostream>
include <conio.h>
using namespace std;
// functions prototypes
void printArray (int arrayName[], int lengthArray);
// global variables
//main
int main ()
{
int firstArray[] = {5, 10, 15};
int secondArray[] = {2, 4, 6, 8, 10};
printArray (firstArray,3);
printArray (secondArray,5);
// end of program
_getch();
return 0;
}
// functions definitions
void printArray(int arrayName[], int lengthArray)
{
for (int i=0; i<lengthArray; i++)
{
cout << arrayName[i] << " ";
}
cout << "n";
}
非常感谢。
TL;DR答案:使用std::vector
。
但我意识到它[
sizeof()
]只考虑它的字节大小,而不考虑数组上有多少元素。
这本身并不是问题:您仍然可以使用sizeof(array) / sizeof(array[0])
来获取数组的大小,但问题是,当传递给函数时,数组会衰减为指向其第一个元素的指针,因此您只能获得sizeof(T *)
(t是数组中元素的类型(。
关于*arrayName++
:
这至少打印了我所有的东西,但超出了我的预期
我甚至不明白是什么启发你用这种方式计算数组的大小。这段代码所做的只是递增数组中的第一个对象,直到它为零。
在运行程序几次后,我意识到我输入的数组的最后一个元素之后的值总是:-858993460
这是一个可怕的假设,它也依赖于未定义的行为。你不能真正确定数组的第一个元素之后的内存中有什么,你甚至不应该访问它
基本上,在C++中,如果你想知道函数中原始数组的大小,那么你必须手动跟踪它(例如,添加一个额外的size_t size
参数(,因为数组传递给函数的方式(记住,它们"衰减"为指针(。如果你想要更灵活的东西,可以考虑使用C++标准库中的std::vector<int>
(或者你想存储的任何类型的对象(——它有一个size()
方法,它可以完全满足你的需求。
第一次尝试
当数组被传递到函数中时,它们会衰减为指针。通常,在数组上使用sizeof
会给出其字节大小,然后除以每个元素的字节大小,得到元素的数量。但现在,由于您有一个指针而不是数组,因此调用sizeof
只会给出指针的大小(通常为4或8字节(,而不是数组本身,这就是失败的原因。
第2次尝试
本例中的while循环假设您的数组以零结尾,这非常糟糕(除非您真的像以null结尾的字符串那样使用零作为终止符(。如果您的数组没有以零结尾,那么您可能正在访问非您的内存,从而调用未定义的行为。另一件可能发生的事情是,数组中间有一个零元素,然后只打印前几个元素。
第3次尝试
您在数组末尾发现的这个特殊值可以随时更改。这个值恰好在此时存在,下次可能会有所不同,所以像这样硬编码是非常危险的,因为你最终可能会访问不属于你的内存。
您的最终代码
这段代码是正确的,通常会将数组的长度与数组本身一起传递(尤其是在用C编写的API中(。只要您没有传递实际大于数组实际长度的长度,此代码就不会引起任何问题,而且这种情况有时会发生,因此也很容易出错。
另一种解决方案
另一种解决方案是使用std::vector
,这是一个容器,它在跟踪其大小的同时,还允许您添加任意多的元素,即在运行时不需要知道大小。所以你可以这样做:
#include <iostream>
#include <vector>
#include <cstddef>
void print_vec(const std::vector<int>& v)
{
std::size_t len = v.size();
for (std::size_t i = 0; i < len; ++i)
{
std::cout << v[i] << std::endl;
}
}
int main()
{
std::vector<int> elements;
elements.push_back(5);
elements.push_back(4);
elements.push_back(3);
elements.push_back(2);
elements.push_back(1);
print_vec(elements);
return 0;
}
值得一看的有用链接
未定义的行为:未定义、未指定和实现定义的行为
数组衰减:什么是数组衰减?
std::矢量:http://en.cppreference.com/w/cpp/container/vector
正如所有其他答案所说,您应该使用std::vector
,或者像您已经做过的那样,将数组的元素数传递给打印函数。
另一种方法是在数组的末尾放置一个sentinel元素(您确信它不会在数组中的值(。在打印功能中,您可以循环浏览元素,当您找到哨兵时,您可以停止。
一个可能的解决方案:您可以使用模板来推导数组长度:
template <typename T, int N>
int array_length(T (&array)[N]) {
return N;
}
请注意,在数组衰减为指针之前,您必须执行操作,但您可以直接或在包装器中使用该技术。
例如,如果您不介意滚动自己的数组包装器:
template <typename T>
struct array {
T *a_;
int n_;
template <int N> array(T (&a)[N]) : a_(a), n_(N) {}
};
你可以这样做:
void printArray(array<int> a)
{
for (int i = 0 ; i < a.n_; ++i)
cout << a.a_[i] << ' ';
}
并称之为
int firstArray[] = {5, 10, 15};
int secondArray[] = {2, 4, 6, 8, 10};
printArray (firstArray);
printArray (secondArray);
关键是模板化构造函数不是explicit
,因此您的数组可以转换为实例,在衰减为指针之前捕获大小。
注:。所示的包装器不适合拥有动态大小的数组,只适合方便地处理静态大小的数组。为了简洁起见,它还缺少各种运算符和一个默认构造函数。通常,对于一般用途,优选std::vector
或std::array
。
。。。OP自己的尝试在其他地方得到了完全解决
使用-858993460值是非常不可靠的,事实上也是不正确的。
可以通过两种方式传递数组的长度:向函数传递一个额外的参数(比如size_t length
(,或者在数组末尾放置一个特殊值。第一种方式是首选的,但第二种方式用于例如通过char*传递字符串。
在C/C++中,不可能在运行时知道数组的大小。如果需要的话,可以考虑使用std::vector
类,它还有其他优点。
当您将数组的长度传递给printArray
时,您可以使用sizeof(array) / sizeof(array[0])
,也就是说,整个数组的字节大小除以单个元素的字节大小,即可获得数组本身的元素大小。
更重要的是,在C++中,你可能会发现学习std::vector
和std::array
对你有利,并且更喜欢它们而不是原始数组——当然,除非你正在做一项要求你学习原始数组的家庭作业。size()
成员函数将为您提供向量中元素的数量。
在C/C++中,本机数组一传递给函数就降级为指针。因此,必须将"length"参数作为函数的参数传递。
C++提供了std::vector集合类。确保在将其传递给函数时,通过引用或指针传递(以避免在传递时复制数组(。
#include <vector>
#include <string>
void printArray(std::vector<std::string> &arrayName)
{
size_t length = arrayName.size();
for(size_t i = 0 ; i < length; ++i)
{
cout << arrayName[i] << ' ';
}
}
int main()
{
std::vector<std::string> arrayOfNames;
arrayOfNames.push_back(std::string("Stack"));
arrayOfNames.push_back(std::string("Overflow"));
printArray(arrayOfNames);
...
}
- Mongodb c++驱动程序:如何查询元素的数组
- 将数组的地址分配给变量并删除
- 从C++本机插件更新Vector3数组
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 数组索引的值没有增加
- 将对象数组的引用传递给函数
- 为char数组调整zlib-zpipe
- 2D数组来自文本输入,中间有空格
- std::向量与传递值的动态数组
- 在c++中用vector填充一个简单的动态数组
- 使用strcpy将char数组的元素复制到另一个数组
- 使用指针从C++中的数组中获取最大值
- C++使用整数的压缩数组初始化对象
- 告诉一个 const char 数组,除了编译时 C 样式的字符串外,它不以 '