c++ - C++语法差异:2D和1D数组(指针算术)

标签 c++ arrays pointers reference transpose

问题
我正在学习C++,并且正在编写代码以转置2D数组,并将反转1D数组
请查看调用。为什么我必须使用reverse(arr, 4)进行反向,而我必须使用transpose(*in_matrix, *out_matrix)进行转置?
编写每个函数签名的方式有两种。两者似乎给出相同的结果。
谢谢。
编辑:我知道如何解决与数组下标。我故意以此方式进行练习。现在,我知道尝试这样做是没有意义的。但是,我添加了一些注释,这些注释归纳于以下答案。
代码

#include <iostream>
using namespace std;

const int LENGTH = 2;
const int WIDTH = 3;

void printArray(const int arr[], const int N) {
    cout << arr[0]; 
    for (int i = 1; i < N; ++i) {
        cout << ", " << arr[i];
    }
    cout << "\n";
}

// void transpose(int* const input, int* const output) { // both these signatures
void transpose(const int input[], int output[]) {        // works (I find the top one clearer)
    for (int i = 0; i < WIDTH; ++i) {
        for (int j = 0; j < LENGTH; ++j) {
            *(output + j * WIDTH + i) = *(input + i * LENGTH + j);
        }
    }
}

// void reverse(int arr[], const int N) { // both these signatures
void reverse(int* arr, const int N) {     // works (I prefer this one)
    for (int i = 0; i < N / 2; ++i) { 
        int temp = *(arr + i);
        *(arr + i) = *(arr + N - 1 - i);
        *(arr + N - 1 - i) = temp;
    }
}

int main() {
    int arr[4] = {2,4,6,8};
    printArray(arr, 4);
    reverse(arr, 4); // this works
    // reverse(*arr, 4); // this doesn't work
    printArray(arr, 4);
     
    int in_matrix[WIDTH][LENGTH];
    in_matrix[0][0] = 1;
    in_matrix[0][1] = 2;
    in_matrix[1][0] = 3;
    in_matrix[1][1] = 4;
    in_matrix[2][0] = 5;
    in_matrix[2][1] = 6;

    int out_matrix[LENGTH][WIDTH];
    // transpose(in_matrix, out_matrix); // this doesn't work
    transpose(*in_matrix, *out_matrix); // this works

    cout << "in_matrix is:\n";
    for (int i = 0; i < WIDTH; ++i) {
        printArray(in_matrix[i], LENGTH);
    }

    cout << "out_matrix is:\n";
    for (int i = 0; i < LENGTH; ++i) {
        printArray(out_matrix[i], WIDTH);
    }
    return 0;
}
答案摘要
LESSON: DO NOT USE pointer-arithmetic for 2D-arrays

              decay
KEY IDEA: arr -----> &arr[0]        type int*
This is also the reason the two function signatures are equivalent.

        // transpose(int* const input, int* const output) // alt.
Signature: transpose(const int input[], int output[])
i.e. it expects an array of ints (or equiv., a pointer to an int)

             (id)
IDENTITY: a[i] = *(a + i)           ALWAYS TRUE

Reason transpose(in_matrix, out_matrix) doesn't work:
           decay
out_matrix -----> &out_matrix[0]    type int(*)[WIDTH]

Reason transpose(*in_matrix, *out_matrix) works:
           (id)             decay
*out_matrix = out_matrix[0] -----> &(out_matrix[0])[0]

最佳答案

在C语言中,数组和指针有些复杂。可以将数组视为附加了一些“大小”信息的指针(该信息未存储在任何地方,但是编译器知道)。因此,当在数组上使用sizeof时,可以提供整个数组内容的大小,而在指针上,它可以提供指针的大小。
当您将数组传递给函数时,大小信息会丢失-实际上,数组会衰减为指针。出于大多数实际目的,可以完全像该类型的一维数组一样使用指向该类型的指针。数组下标符号([])也可以用于使用指针访问连续的元素。
但是,对于2D阵列,这变得更加复杂。 2D数组和双指针可以使用a[i][j]形式的相同访问语法,但它们不可互换。 2D数组衰减为指向数组的指针,而双指针为指向指针的指针。
回到您的问题,编写函数签名的两种方式本质上是等效的,因为一维数组在传递给函数时会衰减为指针。因此void reverse(int* arr, const int N) void reverse(int arr[], const int N)相同。
但是,在转置函数中,您正在传递2D数组。它将衰减为指向数组的指针。但是在函数声明中,您将这些参数接受为数组(或实际上是指针)。由于C的怪异,这种方法仍然可以正常工作。2D数组也可以被视为一个大的1D数组,其中的行接一个接一个地排列。但是,这不是最佳方法。这也反射(reflect)了以下事实:将数组名称传递给转置函数时必须取消引用该数组名称,因为它需要一个1D数组(或指针)而不是2D数组(或指向数组的指针)。
而且,与使用笨拙的指针算法相比,C / C++提供了一种更为优雅的方法来访问数组。因此,以下方法是我推荐的方法。它的工作方式应与您最初发布的代码完全相同,但更简洁,可读性更好。

#include <iostream>
using namespace std;

const int LENGTH = 2;
const int WIDTH = 3;

void printArray(const int arr[], const int N) {
    cout << arr[0]; 
    for (int i = 1; i < N; ++i) {
        cout << ", " << arr[i];
    }
    cout << "\n";
}

void transpose(const int input[][LENGTH], int output[][WIDTH]) {
    for (int i = 0; i < WIDTH; ++i) {
        for (int j = 0; j < LENGTH; ++j) {
            output[j][i] = input[i][j];
        }
    }
}

void reverse(int* arr, const int N) {
    for (int i = 0; i < N / 2; ++i) { 
        int temp = arr[i];
        arr[i] = arr[N - 1 - i];
        arr[N - 1 - i] = temp;
    }
}

int main() {
    int arr[4] = {2,4,6,8};
    printArray(arr, 4);
    reverse(arr, 4);
    printArray(arr, 4);
     
    int in_matrix[WIDTH][LENGTH];
    in_matrix[0][0] = 1;
    in_matrix[0][1] = 2;
    in_matrix[1][0] = 3;
    in_matrix[1][1] = 4;
    in_matrix[2][0] = 5;
    in_matrix[2][1] = 6;

    int out_matrix[LENGTH][WIDTH];
   
    transpose(in_matrix, out_matrix);

    cout << "in_matrix is:\n";
    for (int i = 0; i < WIDTH; ++i) {
        printArray(in_matrix[i], LENGTH);
    }

    cout << "out_matrix is:\n";
    for (int i = 0; i < LENGTH; ++i) {
        printArray(out_matrix[i], WIDTH);
    }
    return 0;
}

关于c++ - C++语法差异:2D和1D数组(指针算术),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62531591/

相关文章:

c++ - 在 C(或 C++)中取消引用指针的语法

c++ - 从文件中获取值以查看它们是 int 还是 string

c++ - 提高期望最大化的绩效

javascript - 如何更好地构建 JSON 中的数组数组

c - 如何访问结构体原始功能之外的成员?

c - 错误: invalid operands to binary * Pointer to a pointer to a matrix

C++函数类型模板参数推导规则

c++ - 结构与对象属性和 C++ 中的 std::vector 的交互

java - 将 Frege 列表转换为 Java 数组

javascript - 如何检查数组的哪些元素相对于位置匹配