已掉线,重新登录

首页 > 绿虎论坛 > 历史版块 > 编程 > 其他编程语言 > 讨论/求助

标题: c++ 数组长度问题

作者: @Ta

时间: 2022-03-15

点击: 3439

不会 c++ 的惨状,最近要写一个 dll,因为我是写 java 的,所以代码都是先写一份 java 的,然后对照着翻译到 c++,int size = (sizeof(result) / sizeof(*result)); 这句是网上搜的 c++ 求数组长度,为什么返回是 1 ?QQ截图20220315140154.jpg

[隐藏样式|查看源码]


『回复列表(9|隐藏机器人聊天)』

1. 太痛苦了,代码要对照写两份,调试两份,本来 java 写好了,输出结果也 ok,但是搬到 c++ 后数据各种偏移,前几天被 c++ 的对象传参坑惨了,今天又冒出一个数组长度问题,本来在 java 直接 length 就有结果,不熟悉 c++ 的语法
(/@Ta/2022-03-15 14:10//)

2.

写 dll 的大佬
小米MIX2s(白)

(/@Ta/2022-03-15 15:36//)

3.

result是一个指针类型,sizeof(result)是指针的长度(32位系统通常为4个字节,64位系统通常为8个字节)
小米8 Explore Edition (透明色)

(/@Ta/2022-03-15 16:48//)

4.

@yiluo不要用传统C风格数组和指针。

无法从作为参数传递过来的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

(/@Ta/2022-03-16 01:59//)

5.

@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

(/@Ta/2022-03-16 00:54//)

6.

@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

(/@Ta/2022-03-16 02:14//)

7.

@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++生活更轻松。

(/@Ta/2022-03-16 01:39//)

8.

@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>

图片.png

(/@Ta/2022-03-16 01:44//)

9. 老虎真是太牛了!
(/@Ta/2022-03-16 10:24//)

回复需要登录

7月6日 17:41 星期天

本站由hu60wap6驱动

备案号: 京ICP备18041936号-1