【问题标题】:Why is my function unable to print an element of a multi-dimensional array using pointers?为什么我的函数无法使用指针打印多维数组的元素?
【发布时间】:2019-10-22 08:10:46
【问题描述】:

我有一个 3 X 3 多维数组,我想使用指针打印第 0 行的所有 3 个元素。

这是我写的代码:

#include <iostream>

void print(int *p){
    for(int i = 0; i < 3; i++){
        std::cout << (*p)[i];
    }
};


int main(void){
    int arr[3][3] = {
        {1,2,3} ,
        {4,5,6} ,
        {7,8,9}
    };
   print(arr);
}

这会引发以下错误:

Main.cpp:5:26: 错误:下标值不是数组、指针或向量

std::cout << (*p)[i];
                 ~~~~^~

Main.cpp:16:4: 错误:没有匹配的函数调用“打印”

print(arr);
   ^~~~~

Main.cpp:3:6:注意:候选函数不可行:第一个参数没有从 'int [3][3]' 到 'int *' 的已知转换

void print(int *p){

据我了解,arr 是指向数组的第一个元素的指针,该元素本身就是一个数组。那么为什么我找不到指针 arr 返回的值的数组 [i] 呢?

【问题讨论】:

  • 尝试将参数类型更改为int **pint p[][](参见this anwer

标签: c++ arrays pointers multidimensional-array


【解决方案1】:

函数print的参数类型为int *

print(int *p)

因此,取消引用表达式(*p)[i] 中的指针,您将获得int 类型的标量对象。您不能将下标运算符应用于int 类型的标量对象。

另一方面,在这个电话中

print(arr);

类型为int[3][3] 的参数被转换为指向其第一个元素的指针。数组元素的类型为int[3]。所以数组隐式转换为指向其第一个元素的指针后的表达式类型为int ( * )[3]

而且错误信息指向了这个问题

Main.cpp:16:4: error: no matching function for call to 'print'

print(arr);
   ^~~~~

因为编译器无法找到名称为 print 且接受 int ( * )[3] 类型参数的函数。

因此函数print的参数应该声明为

print( int p[][3] )

print( int ( *p )[3] )

由于数组在函数中没有改变,它应该用限定符const声明。

这种情况下的函数定义看起来像(如果你想使用指针)

void print( const int p[][3] )
{
    for( const int ( *row )[3] = p; row != p + 3; ++row ) 
    {
        for ( const int *col = *row; col != *row + 3; ++col )
        {
            std::cout << *col << ' ';
        }
        std::cout << '\n';
    }
}

这是一个演示程序。

#include <iostream>

void print( const int p[][3] )
{
    for( const int ( *row )[3] = p; row != p + 3; ++row ) 
    {
        for ( const int *col = *row; col != *row + 3; ++col )
        {
            std::cout << *col << ' ';
        }
        std::cout << '\n';
    }
}

int main() 
{
    const size_t N = 3;
    int arr[N][N] = 
    {
        { 1, 2, 3 } ,
        { 4, 5, 6 } ,
        { 7, 8, 9 }
    };

    print( arr );

    return 0;
}

它的输出是

1 2 3 
4 5 6 
7 8 9

但是,这种方法有一个严重的缺点。该函数使用幻数3

最好重写函数至少像

#include <iostream>

const size_t N = 3;

void print( const int p[][N], size_t rows )
{
    for( const int ( *row )[N] = p; row != p + rows; ++row ) 
    {
        for ( const int *col = *row; col != *row + N; ++col )
        {
            std::cout << *col << ' ';
        }
        std::cout << '\n';
    }
}

int main() 
{
    int arr[][N] = 
    {
        { 1, 2, 3 } ,
        { 4, 5, 6 } ,
        { 7, 8, 9 }
    };

    print( arr, sizeof( arr ) / sizeof( *arr ) );

    return 0;
}

您还可以添加一个带有默认参数的参数。例如

std::ostream & print( const int p[][N], size_t rows, std::ostream &os = std::cout )
{
    for( const int ( *row )[N] = p; row != p + rows; ++row ) 
    {
        for ( const int *col = *row; col != *row + N; ++col )
        {
            os << *col << ' ';
        }
        os << '\n';
    }

    return os;
}

例如

#include <iostream>

const size_t N = 3;

std::ostream & print( const int p[][N], size_t rows, std::ostream &os = std::cout )
{
    for( const int ( *row )[N] = p; row != p + rows; ++row ) 
    {
        for ( const int *col = *row; col != *row + N; ++col )
        {
            os << *col << ' ';
        }
        os << '\n';
    }

    return os;
}

int main() 
{
    int arr[][N] = 
    {
        { 1, 2, 3 } ,
        { 4, 5, 6 } ,
        { 7, 8, 9 }
    };

    print( arr, sizeof( arr ) / sizeof( *arr ) ) << '\n';

    return 0;
}

最后你可以写一个模板函数了。

#include <iostream>

template <typename T, size_t N>
std::ostream & print( const T ( &p )[N][N], std::ostream &os = std::cout )
{
    for( const int ( *row )[N] = p; row != p + N; ++row ) 
    {
        for ( const int *col = *row; col != *row + N; ++col )
        {
            os << *col << ' ';
        }
        os << '\n';
    }

    return os;
}

int main() 
{
    const size_t N = 3;

    int arr[][N] = 
    {
        { 1, 2, 3 } ,
        { 4, 5, 6 } ,
        { 7, 8, 9 }
    };

    print( arr ) << '\n';

    return 0;
}

【讨论】:

    【解决方案2】:

    数组arr 的第一个元素的类型为int[3]。因为所谓的二维数组在语言上就是数组的数组

    因此arr 不能等同于int*,只能等同于int[][3]int(*)[3]

    void print(int p[][3]){
        for(int i = 0; i < 3; i++){
            std::cout << p[0][i];
        }
    };
    

    void print(int (*p)[3]){
        for(int i = 0; i < 3; i++){
            std::cout << (*p)[i];
        }
    };
    

    将是您的函数的正确签名。任何将多维数组表示为指针的尝试都需要显式转换并在函数中将其洗回正确的类型,否则将被视为未定义行为,即使大多数实现都允许这样做。

    【讨论】:

      【解决方案3】:

      在我看来,以前的所有答案都没有解决主要问题。

      问题是,如何将一个普通的旧 C 数组传递给函数。

      如果你想将一个普通的旧 C 数组传递给一个函数,你有两种可能性。

      • 通过引用传递
      • 按指针传递

      看来你想通过引用传递。但是你使用了错误的语法。

      请看:

      void function1(int(&m)[3][4])   // For passing array by reference
      {}
      void function2(int(*m)[3][4])   // For passing array by pointer
      {}
      
      int main()
      {
          int matrix[3][4]; // Define 2 dimensional array
      
          function1(matrix);  // Call by reference
          function2(&matrix); // Call via pointer 
          return 0;
      }
      

      你传递给函数的是一个指向 int 数组的衰减指针。

      只需更正语法即可。

      附加提示:

      不要在 C++ 中使用纯 C 样式的数组。绝不。请使用 STL 容器。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多