【问题标题】:How to reference two dimensional array?如何引用二维数组?
【发布时间】:2015-08-29 06:41:46
【问题描述】:

我知道二维数组作为一维数组存储在内存中。 因此,按照相同的逻辑,我尝试使用单个指针通过引用传递数组,就像对一维数组所做的那样。 以下是我的代码:

#include<stdio.h>
void display(int *s)
{
    int i,j;
    for(i=0;i<3;i++)
    {
        for(j=0;j<4;j++)
        {
            printf("%d ",s[i][j]);
        }
        printf("\n");
    }
}
int main()
{
    int s[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
    printf("address of the array is %p\n",s);
    printf("value is %p\n",*s);
    int i;
    printf("address of the repective array is\n");
    for(i=0;i<3;i++)
    {
        printf("address of the array is %p\n",s[i]);
    }
    display(s);
    return 0;
}

当我尝试编译这个得到以下消息:

 twodarray.c: In function ‘main’:
twodarray.c:25:2: warning: passing argument 1 of ‘display’ from    incompatible pointer type [enabled by default]
  display(s);
  ^
twodarray.c:2:6: note: expected ‘int **’ but argument is of type ‘int (*)[4]’
 void display(int *s[3])
      ^

当我运行上面的代码时,我得到分段错误错误。

【问题讨论】:

  • 看起来您已经初始化了一个二维数组,但试图将它作为一维数组传递给函数。不过我可能是错的
  • 是的,它是一个二维数组,但是二维数组和内存中的一维数组不一样吗?
  • void display(int *s) 改成void display(int s[3][4]) 如果你想printf("%d ",s[i][j]);
  • void display(int s[][4])void display(int (*s)[4])
  • @ user2738777 ,二维数组的名称被转换为指向第一个数组的指针,而不是指向int的指针或指向int的指针。谷歌“将二维数组传递给函数”或尝试我或@BLUEPIXY 建议的更改

标签: c arrays pointers


【解决方案1】:

函数参数被声明为类型int *

void display(int *s)

而作为参数传递给函数的原始数组具有类型

int [3][4]

隐式转换为指向其第一个具有类型的元素的指针

int ( * )[4]

如您所见,int *int ( * )[4] 是两种不同的类型,并且没有从一种类型到另一种类型的隐式转换。

此外,由于函数参数的类型为int *,因此您不能在函数表达式s[i][j] 中写入。因为如果将下标运算符应用于此指针,例如s[i],则此表达式是int 类型的标量对象。它不是指针。所以你可能不会第二次应用下标运算符。

您必须将参数显式转换为函数调用中参数的类型。例如

display( ( int * )s );

你想要的是以下

#include <stdio.h>

void display( int *a, size_t m, size_t n )
{
    for ( size_t i = 0; i < m; i++ )
    {
        for ( size_t j = 0; j < n; j++ )
        {
            printf( "%2d ", a[i * n + j] );
        }
        printf( "\n" );
    }
}

int main( void )
{
    int a[3][4] = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } };

    printf( "The address of the array is %p\n", ( void * )a );

    printf( "The address of the first row is %p\n", ( void * )*a );

    printf("The address of the respective array rows are\n");
    for ( size_t i = 0; i < 3; i++ )
    {
        printf( "address of row %zu is %p\n", i, ( void * )a[i] );
    }

    display( ( int * )a, 3, 4 );

    return 0;
}

程序输出可能如下所示

The address of the array is 0xbf85d2dc
The address of the first row is 0xbf85d2dc
The address of the respective array rows are
address of row 0 is 0xbf85d2dc
address of row 1 is 0xbf85d2ec
address of row 2 is 0xbf85d2fc
 1  2  3  4 
 5  6  7  8 
 9 10 11 12 

虽然最好按照以下方式声明函数,以避免不必要的强制转换和复杂的函数实现

void display( int ( *a )[4], size_t m );

【讨论】:

    【解决方案2】:

    像您在此处定义的那样的静态二维数组在内存中以顺序一维数组的形式排列。但它不能像你尝试的那样使用。通常编译器甚至不会生成此代码的二进制文件。

    从技术上讲,您可以通过将指针转换为int* 来调用display() 函数。这并没有多大帮助,因为在函数内部它是二维索引的,编译器不知道维度是什么。

    这样想:如果分配一个 100 个整数的线性内存块,是否意味着它是一个大小为 10x10、2x50 或 4x25 的数组?没有办法知道,所以你不能将它索引为二维数组。此外,甚至可能不知道内存块有多大。

    但是,您可以将其索引为一维数组,然后手动将索引乘以 s[i*4+j]。之所以可行,是因为如上所述,静态数组线性存储在内存中,您需要手动告诉如何读取它。

    只是想知道您是如何设法真正编译该代码的。

    【讨论】:

      【解决方案3】:

      int[3][4] 类型的数组不能转换为int**int *[]int* 类型的指针。

      问题是,

      int s[3][4];
      

      实际上将存储在物理上连续的内存中。要访问 3x4 数组的任意部分,函数 display 需要知道数组的维度。

      所以你应该改变你的功能:

      void display(int (*s)[4])
      

      或使用更灵活的技术 (Passing multidimensional arrays as function arguments in C)。

      【讨论】:

      • 对,指向第一行的指针。有关更多详细信息,您可以查看stackoverflow.com/q/13554244/3235496int (*ptr)[4] = s 第一行(s[0][0] 的地址)。 ++ptr第二行(s[1][0]的地址)。
      【解决方案4】:

      二维数组按行存储在内存中。因此,首先将存储数组元素 s[0][0],然后存储 s[0][1],s[0][2],s[0][3],s[1][0].. . 同样。

      您已将指向被调用函数中的一维数组的指针作为参数。你所能做的就是改变 printf("%d ",s[i][j]);声明 printf("%d",*(s + i + j));,这样就可以了。

      最后一个 printf 语句应编辑为 printf("%d ",*(s + 4*i + j));正如以下评论所建议的那样。

      【讨论】:

      • 不会,s + i + j 缺少一个索引器的乘数。
      • 请查看代码中正在实现的 for 循环,您将了解它是如何工作的。
      • 是的,循环是 0..2 和 0..3,所以如果你把它们加起来,你会得到 0, 1, 2, 3, 1, 2, 3, 4, 2, 3, 4, 5...(不是我对答案的反对,只是想说)
      猜你喜欢
      • 2019-07-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-30
      • 1970-01-01
      • 2012-04-10
      • 1970-01-01
      相关资源
      最近更新 更多