标题: c++ 数组长度问题
时间: 2022-03-15
『回复列表(9|隐藏机器人聊天)』
无法从作为参数传递过来的C数组指针获取数据长度(6楼代码注释里解释了为什么),必须单独传递数据长度,或者使用“结束标记”(比如像C字符串一样使用'\0'
作为结束)。
应该使用和Java类似的容器对象(在C++中称为“标准模板库”STL)。
比如STL的“向量”容器(std::vector<>
)就和Java的ArrayList<>
非常类似。
#include <stdio.h>
#include <vector>
using namespace std;
int main() {
vector<float> result;
for (int i=0; i<100; i++) {
result.push_back(i * 3.1415926);
}
printf("result size: %d\n", result.size());
printf("result[12] = %f\n", result[12]);
result[33] = 12315.0;
printf("result[33] = %f\n", result[33]);
result.resize(51);
printf("result size: %d\n", result.size());
return 0;
}
result size: 100
result[12] = 37.699112
result[33] = 12315.000000
result size: 51
@yiluo,如果想像Java一样自动管理内存,可以使用智能指针:
#include <stdio.h>
#include <vector>
#include <memory>
using namespace std;
void fixBar(shared_ptr<vector<float>> result) {
printf("fixBar: result size: %d\n", result->size());
for (int i=0; i<result->size(); i++) {
result->at(i) += 12315.0;
}
result->push_back(31152.0);
}
int main() {
// auto自动推断result的类型,它在此处相当于shared_ptr<vector<float>>。
// make_shared创建一个由C++自动管理生命周期的共享对象,
// 可以把该对象传递到任何地方,都不会失效,并且始终是同一个对象。
// 和Java一样,在该对象的所有引用都释放后,该对象自动释放。
auto result = make_shared<vector<float>>();
for (int i=0; i<100; i++) {
// result是引用类型而不是值类型,所以使用“->”取代“.”作为方法调用操作符。
result->push_back(i * 3.1415926);
}
printf("result size: %d\n", result->size());
// 因为result现在是引用类型,所以对它进行数组操作需要先解引用。
// 由于操作符优先级的关系,需要加括号。
(*result)[12] = 12315.0;
printf("result[12] = %f\n", (*result)[12]);
// 或者使用->at()方法,可读性更好。
result->at(12) = 12306.0;
printf("result[12] = %f\n", result->at(12));
printf("result[33] = %f\n", result->at(33));
result->resize(51);
printf("result size: %d\n", result->size());
fixBar(result);
printf("after fixBar: result size: %d\n", result->size());
printf("result[12] = %f\n", result->at(12));
printf("result[33] = %f\n", result->at(33));
return 0;
}
result size: 100
result[12] = 12315.000000
result[12] = 12306.000000
result[33] = 103.672554
result size: 51
fixBar: result size: 51
after fixBar: result size: 52
result[12] = 24621.000000
result[33] = 12418.672852
@yiluo,如果想用固定大小的数组,可以用std::array
。
如果想把数组作为参数传递给只接收传统C风格数组的外部函数,可以使用data()
方法。
#include <stdio.h>
#include <memory>
#include <array>
#include <vector>
using namespace std;
// 一个只能接收C数组的外部函数
// 注意:C数组必然需要单独传递大小,除非它使用特殊的取值作为结束标记(比如'\0')。
void ExternalFunction1(float result[], int size) {
printf("fake result size: %d\n", sizeof(result));
printf("real result size: %d\n", size);
printf("result[%d] = %f\n", size-1, result[size-1]);
}
// 还是只能接收C数组的外部函数
// C数组之所以需要单独传递大小,是因为参数中的C数组写法(xxx[])实际上是C指针(*xxx)的语法糖。
// 所以其实该函数和上面的函数完全相同。
void ExternalFunction2(float *result, int size) {
// 这获取到的是谁的大小?
// 首先思考一个问题:result是什么?是一个float类型的指针。
// 所以这获取到的自然是指针的大小。
// 在32位程序中,一个指针4字节。在64位程序中,一个指针8字节。
printf("fake result size: %d\n", sizeof(result));
// 有没有其他方法仅通过指针就能获取它指向的数据大小?
// 答案是没有。指针所包含的全部信息,只是一个内存地址:一个,不是一批,只有开始,没有结束。
// 所以光靠指针,我们只能找到第一个数据,然后我们只能沿着指针往后移动,找到后续数据。
// 如果数据本身不能指示自己在哪里结束,并且也没有额外的参数告诉我们数据在哪里结束,
// 光靠指针我们当然不知道数据在哪里结束。
// C风格指针必须结合额外信息才能得知数据的结束位置,可以是这些信息:
// 1. 数据自己标识自己哪里结束。比如放一个'\0'作为结束标记。C风格字符串就是这么做的。
// 2. 额外传递长度参数,大部分C风格函数都是这么做的,通常有两个参数,一个指针一个长度。
// 3. 分别传递开始和结束指针,有些迭代器函数是这么做的。用结束指针减去开始指针就是数据长度。
printf("real result size: %d\n", size);
printf("result[%d] = %f\n", size-1, result[size-1]);
}
int main() {
// 固定大小的数组对象,模板参数第一个是类型,第二个是数组大小
auto result1 = make_shared<array<float, 100>>();
// 默认为空的数组对象,相当于Java的ArrayList
auto result2 = make_shared<vector<float>>();
for (int i=0; i<result1->size(); i++) {
result1->at(i) = i * 3.1415926; // 固定大小,所以直接赋值
result2->push_back(i * 3.1415926); // 默认为空,所以需要插入
}
printf("result1 size: %d, result2 size: %d\n", result1->size(), result2->size());
printf("result1[12] = %f, result2[12] = %f\n", result1->at(12), result2->at(12));
result1->at(33) = 12315.0;
result2->at(33) = 12315.0;
printf("result1[33] = %f, result2[33] = %f\n", result1->at(33), result2->at(33));
printf("--- result 1 ---\n");
// 如何把数组对象传递给只能接收传统C风格数组指针的外部函数?
// 使用->data()方法就可以。
ExternalFunction1(result1->data(), result1->size());
printf("--- result 2 ---\n");
ExternalFunction1(result2->data(), result2->size());
return 0;
}
result1 size: 100, result2 size: 100
result1[12] = 37.699112, result2[12] = 37.699112
result1[33] = 12315.000000, result2[33] = 12315.000000
--- result 1 ---
fake result size: 8
real result size: 100
result[99] = 311.017670
--- result 2 ---
fake result size: 8
real result size: 100
result[99] = 311.017670
@yiluo,可以在这里找到标准模板库里可用的容器:https://zh.cppreference.com/w/cpp/container
这是字符串库(std::string
)的文档:https://zh.cppreference.com/w/cpp/string
智能指针的文档:https://zh.cppreference.com/w/cpp/memory/shared_ptr
要使用某个容器时,首先需要引用它所在的头文件。
比如std::vector定义于头文件 <vector>,所以开头要加#include <vector>
。