C语言 二维数组与指针笔记

今天分析了C语言二维数组和指针的基本理解,感觉有点懵。。。代码记录一下,如果有大神临幸发现哪里有误,欢迎指正~~~

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//void func(int p[][])  //这样写等同于void func(int **p)   p++移动了四个字节,(*p)++移动了四个字节,不符合二维数组规律
//{
//}


//列优先输出的函数(即竖着输出)
void func(int p[][4], int a, int b)  //这样写是正确的,这样写等同于void func(int (*p)[4])   p++移动16个字节,(*p)++移动了4个字节,a和b是为了保持维度,a表示列,b表示行
{
    for (int i = 0; i < a; i++)
    {
        for (int j = 0; j < b; j++)
        {
            printf("%d
", *(*(p + j) + i));
        }
    }
}

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

    //printf("%d
", sizeof(array[0]));  // 结果为16,妈的,array[0]竟然不是指针,而是一个数组的名称,
    //printf("%d
", sizeof(array));    //结果48
 func(array, 
sizeof(array[0]) / sizeof(int), sizeof(array) / sizeof(array[0]));//
第二个参数是列数,第三个参数为行数
//array[0]并不是一个变量,是二维数组中第0行的首地址
//和下面的:      *(p + 0) + 1;    代表int *向后位移了一个位置   道理上应该是相同的。

        //在二维数组中*array代表的也是数组的首地址,而一维数组中*array代表的是第一个元素的值
    //printf("%d  %d  %d  %d
", array, *array, &array, &array[0][0], array[0]);

   //
printf("%d ", array + 1); //
printf("%d
", array[0] + 1);
        //结果为array + 1  移动了16个字节
        //        array[0] + 1 移动了4个字节
        //可以这样理解,array + 1看成连长,array[0] + 1看成排长,连长每次走一行(即走4个数,14个字节),排长每次走一列(即走一个数,4个字节)


    //int *p = array;  //指向一维数组的指针

   
//int (*p)[4];
是一个变相的二级指针
    //p = array;
    //*(p + 0) + 1;    代表int *向后位移了一个位置

    //for (int i = 0; i < 4; i++)
    //{
    //    for (int j = 0; j < 3; j++)
    //    {
    //        printf("%d
", *(*(p + j) + i));
    //    }
    //}
    //*(p + 0)   代表的是指向第一行的指针。所以*(p + 0) + 1  是指向第一行第二个元素的位置
    //printf("---------------
");

    //-----------
    //p + 1;   //代表的是排长,每次走一行
    //p[0][0] = *(*(p + 0) + 0);  //代表的是连长,每次走一个数

    //printf("%d
", *(*(p+1)));  //第一行第0个元素

    system("pause");
    return 0;
}

分析如下:

黄色代码部分:输出的地址完全相同,所以二维数组和一维数组的一点区别是:   在二维数组中*array代表的也是数组的首地址,而一维数组中*array代表的是第一个元素的值

红色代码部分:      相对于黄色代码部分,红色代码结果为:     array + 1 移动了16个字节  , array[0] + 1 移动了4个字节;

  因为array是数组的首地址,而且是一个二维数组,所以array+1  应该是移动一行,即4个数字,array[0]是二维数组的“第一行数组”的首地址,所以+1应该是在第一行数组里面移动指针;

( 如果 int  *p = &i;  那么p+1的结果就会移动4个字节,如果 char  *p = &i;  那么p+1的结果就会移动1个字节,  这里其实也是相同的道理,只是不好理解。。。)

也可以使用排长和连长的例子来理解,把array看成连长,把array[0]看成排长,连长每次审阅,会一行一行的走,排长审阅,则会一排一排的走,所以array(连长)每次走16个字节,array[0]每次走4个字节。

 

橘黄色代码部分:       定义二级指针的时候,一般会这样定义,int (*p)[4];

这里有一个“指针数组”和“数组指针”的概念,图示和代码如下:

            指针数组:                                                                                    数组指针

          int *p[5];                                                                           int (*P)[10];

C语言 二维数组与指针笔记C语言 二维数组与指针笔记

#include <stdio.h>
#include <stdlib.h>

int main()
{
           //指针数组
           char *s[10];   //是一个数组,该数组中有10个char *指针,每个指针指向一个字符
          printf( "%d
" ,sizeof (s[0]));  //4

           //数组指针
           char (*s1)[10];    //是一个指针变量,该指针变量指向一个char[10];不能指向其他任何char[n]数组
          printf( "%d
" , sizeof (s1));   //4

          system( "pause" );
           return 0;
}

所以:int (*p)[4]; 是一个数组指针,指向一个4个元素的数组,

p = array;    也就是把二维数组的首地址赋给p,array也是一个地址(相当于一个指针,但如果我们用sizeof(array)会发现其实不是一个指针),所以p其实是一个变相的二级指针(你不信的话可以利用**p测试看是否能够取到数组的第一个元素)

所以    *(p + 0) + 1; 代表int *向后位移了一个位置   也就不难理解了, p是一个二级指针, p+0代表的其实就是第一行数组的首地址。*(p+0) 还是一个指针,  也就是一个int * 类型的变量(指针也是一个变量),*(p + 0) + 1;代表的就是int *向后位置了一个位置

*(p + 0) 代表的是指向第一行的指针。所以*(p + 0) + 1 是指向第一行第二个元素的位置的指针,*(*(p + 0) + 1 ) 就是第一行第二个元素的值;

灰色颜色代码的部分:     这样写的原因就是直接把二维数组的维度发过去,因为在接收端函数方是不知道二维数组的维度的,而且这样写以后更改数组的维度的时候,不用更改其他代码。