C++:数组作为参数进行传递


📌 来自C++ primer中的6.2.4部分

数组的特性

  • 数组名称作为指向其中第一个元素的pointer;
  • 数组不能被copy
    int a[] = {1, 2, 3};
    int b[3] = a;  // 错误,不能用一个数组初始化另一个数据
    b = a; // 错误,不能数组赋值和copy
    

    📌 有些编译器允许数组赋值,但是这种是作为compiler extension存在的,不是标准支持的语法,跨编译器时可能会存在问题。

数组作为函数参数

基于数组的特性,不能复制,因此无法使用数组作为函数的形参,也就不能按值传递数组;但是,可以利用另一个特性,向函数传递数组名称作为第一个元素的指针。

声明数组作为函数参数

// 三种声明等价,忽略它们定义的样子
void print(const int * ); 
void print(const int[]);
void print(const int[10]);

上述三种方式中,函数的参数均为const int*. 因此,当函数调用时,判断传入的参数时,只会按照这个类型进行匹配。

int i = 0;
int j[2] = {0, 1};

print(&i); // ok, int *类型,可以传入
print(j);  // ok, 数组的维度不相关

这里,数组的维度即使不匹配也没问题,因为不影响。

但是,因此函数也不知道数组的大小了,为了进行遍历,需要一些额外的方法,共有3种。

依赖数组中的变量类型存在标识符

典型的就是C风格的字符串,结尾有“\0” null charactor. 因此,可以根据这个判断是否到结尾,如下:

void print(const char *cp) {
    if (cp){
        while ( *cp){
            cout << *cp++;
        }
    }
}

这种方法对于字符串等类型友好,但是不适用于如int等类型的数据,因为没有结尾标识符。

传递数组的收尾指针

void print(const int * beg, const int * end) {
    while (beg != end){
        cout << *beg << endl;
        beg++;
    }
}

int j[2] = {0, 1};
print(begin(j), end(j));

其中:

  • begin返回第一个元素的指针;
  • end返回最后一个元素之后的指针,注意,这个指针指向的元素不在数组中,但是是有效的指针value;

这种方法,通用,安全,不受类型的限制。

显式传递数组长度

void print(const int ia[], size_t size) {
    for (size_t i = 0; i != size; ++i) {
        cout << ia[i] << endl;
    } 
}

int j[] = { 0, 1 }; 
print(j, end(j) - begin(j));

这种方法也是安全的,但是要保证size与ia的长度是一致的。

一些注意事项

  • 上述函数的定义中,参数均为 pointer to const;

    When a function does not need write access to the array elements, the array parameter should be a pointer to const. A parameter should be a plain pointer to a nonconst type only if the function needs to change element values.

  • reference对于数组参数的影响 对于一个数组变量,可以定义它的reference, 对于函数参数中数组,也可以定义数组的reference,但是会有一点迷惑。
    void print(int (&arr)[10]) {
        for (auto elem : arr)
            cout << elem << endl; 
    }
    
    // 1. arr[10] stores ten reference to ints.
    f(int &arr[10])
    // 2. 表示,arr is a reference to an array of ten ints, (&arr)中括号必须存在
    f(int (&arr)[10])
    
    对第一个来说,因为数组的维度是数组类型的一部分,当调用函数print(int (&arr)[10])时,必须保证维度相同。
    int i = 0, j[2] = {0, 1};
    int k[10] = {0,1,2,3,4,5,6,7,8,9};
    print(&i); // error: argument is not an array of ten ints 
    print(j); // error: argument is not an array of ten ints 
    print(k); // ok: argument is an array of ten ints
    

文章作者: alex Li
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 alex Li !
  目录