写 dll 的大佬 小米MIX2s(白)
result是一个指针类型,sizeof(result)是指针的长度(32位系统通常为4个字节,64位系统通常为8个字节) 小米8 Explore Edition (透明色)
@yiluo,不要用传统C风格数组和指针。
无法从作为参数传递过来的C数组指针获取数据长度(6楼代码注释里解释了为什么),必须单独传递数据长度,或者使用“结束标记”(比如像C字符串一样使用'\0'作为结束)。
'\0'
应该使用和Java类似的容器对象(在C++中称为“标准模板库”STL)。
比如STL的“向量”容器(std::vector<>)就和Java的ArrayList<>非常类似。
std::vector<>
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()方法。
std::array
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,既然Java是完全的面向对象编程,所以改成C++的时候,就应该用对象取代对象。
std::string
std::vector
std::list
std::unordered_map
它们是完全对应的数据结构,无论是性能、实现方法还是实际用起来都很类似。 再结合智能指针,就可以实现和Java一样的面向对象+自动内存管理了。
早日抛弃C风格字符串和数组,让C++生活更轻松。
@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>。
#include <vector>
写 dll 的大佬
小米MIX2s(白)
result是一个指针类型,sizeof(result)是指针的长度(32位系统通常为4个字节,64位系统通常为8个字节)
小米8 Explore Edition (透明色)
@yiluo,不要用传统C风格数组和指针。
无法从作为参数传递过来的C数组指针获取数据长度(6楼代码注释里解释了为什么),必须单独传递数据长度,或者使用“结束标记”(比如像C字符串一样使用
'\0'
作为结束)。应该使用和Java类似的容器对象(在C++中称为“标准模板库”STL)。
比如STL的“向量”容器(
std::vector<>
)就和Java的ArrayList<>
非常类似。@yiluo,如果想像Java一样自动管理内存,可以使用智能指针:
@yiluo,如果想用固定大小的数组,可以用
std::array
。如果想把数组作为参数传递给只接收传统C风格数组的外部函数,可以使用
data()
方法。@yiluo,既然Java是完全的面向对象编程,所以改成C++的时候,就应该用对象取代对象。
std::string
代替Java String。std::array
代替简单Java数组。std::vector
代替Java ArrayList。std::list
代替Java LinkedList。std::unordered_map
代替Java HashMap。它们是完全对应的数据结构,无论是性能、实现方法还是实际用起来都很类似。
再结合智能指针,就可以实现和Java一样的面向对象+自动内存管理了。
早日抛弃C风格字符串和数组,让C++生活更轻松。
@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>
。