C++数组作为函数参数:从基础语法到高效传递的完整指南

1次阅读
没有评论

共计 1640 个字符,预计需要花费 5 分钟才能阅读完成。

image.webp

为什么数组传参让人头疼?

刚学 C ++ 时,我以为数组传参和 int 传参一样简单,直到遇到这个场景:

C++ 数组作为函数参数:从基础语法到高效传递的完整指南

void printSize(int arr[]) {cout << sizeof(arr); // 输出 8(指针大小)而不是数组大小!}

这是因为 数组在传参时会退化为指针——这是 C ++ 从 C 继承的特性。具体表现为:

  1. sizeof 失灵:函数内获取的是指针大小而非数组尺寸
  2. 长度丢失:必须额外传递 size 参数(容易出错)
  3. 类型弱化:无法区分指向单个元素的指针和数组指针

三种传统传参方式对比

方式 1:形参声明为数组(实际仍是指针)

void func(int arr[5]); // 编译器视为 int* arr

– 优点:写法直观
– 缺点:方括号内的数字会被忽略,本质还是指针

方式 2:直接传递指针

void func(int* arr, size_t size);

– 优点:明确需要额外传递大小
– 缺点:手动管理 size 容易出错

方式 3:传递数组引用(C++ 特有)

template<size_t N>
void func(int (&arr)[N]); // N 会被自动推导

– 优点:保留数组类型和长度信息
– 缺点:只能接受静态数组,语法稍复杂

现代 C ++ 的救星

std::array(C++11)

#include <array>

void process(std::array<int, 5>& arr) {for(int num : arr) {/* 安全遍历 */}
}

– 特点:固定大小、自带边界检查、支持 STL 算法

std::span(C++20)

#include <span>

void analyze(std::span<int> data) {cout << data.size(); // 自动携带大小信息
}

– 特点:兼容 C 数组和容器、运行时大小检查、零开销抽象

安全遍历的两种姿势

方法 1:模板非类型参数(编译期确定大小)

template<typename T, size_t N>
void printArray(const T (&arr)[N]) {for(size_t i=0; i<N; ++i) 
        cout << arr[i] << ' ';
}

方法 2:range-based for 循环(C++11)

void safeTraversal(std::array<int, 5>& arr) {for(auto& elem : arr) { // 自动边界控制
        elem *= 2; 
    }
}

新手常踩的三个坑

陷阱 1:越界访问

错误示范:

void fill(int* arr, int size) {for(int i=0; i<=size; ++i) // 多了一次!arr[i] = i; 
}

修复方案:

// 使用 std::array 或 span 的 at()方法(会抛异常)arr.at(i) = i; 

陷阱 2:混淆静态 / 动态数组

错误示范:

int staticArr[5];
int* dynamicArr = new int[5];

// 编译错误!动态数组不能这么用
template<size_t N>
void func(int (&arr)[N]);

修复方案:

// 对动态数组统一使用 span
void handleArray(std::span<int> arr);

陷阱 3:二维数组传参

错误写法:

void print2D(int arr[][]); // 非法!

正确姿势:

// 指定列数(行数可自动推导)template<size_t Cols>
void print2D(int (&arr)[][Cols]);

性能优化建议

通过 Compiler Explorer 观察不同传参方式的汇编代码:

  1. 指针传递:生成最简短的指令,但需手动维护 size
  2. 引用传递:与指针等效,但能保留类型信息
  3. std::array:零开销抽象,适合高频调用
  4. std::span:引入少量边界检查开销(可编译优化)

高频场景建议:
– 对性能临界区使用const T*+size_t
– 常规代码优先用 span/array

思考题

如何设计一个同时接受 C 风格数组和 STL 容器的泛型函数?提示:可以结合模板和 std::data()/std::size() 函数。

(完整示例代码可在 GitHub 示例仓库查看)

正文完
 0
评论(没有评论)