• 第34课 多维数组和多维指针


    1. 指向指针的指针(多维指针

    (1)指针的本质变量,会占用一定的内存空间

    (2)可以定义指针的指针来保存指针变量的地址值

    (3)指针是个变量,同样也存在传值调用与传址调用

    【实例分析】重置动态空间的大小

      1 #include <stdio.h>
      2 
      3 #include <malloc.h>
      4 
      5  
      6 
      7 int reset(char**p,int size,int new_size)
      8 
      9 {
     10 
     11     int ret = 1;
     12 
     13     int i = 0;
     14 
     15     int len = 0;
     16 
     17     char* pt = NULL;
     18 
     19     char* pp = *p;
     20 
     21  
     22 
     23     if((p != NULL)&&(new_size > 0))
     24 
     25     {
     26 
     27         pt = (char*)malloc(new_size);
     28 
     29        
     30 
     31         len = (size < new_size)?size : new_size;//取较小者
     32 
     33        
     34 
     35         //复制原内容
     36 
     37         for(i=0; i<len;i++){
     38 
     39             *pt = *pp++;
     40 
     41         }
     42 
     43        
     44 
     45         free(*p); //释放原空间
     46 
     47         *p = pt;  //*p指针指向新空间
     48 
     49     }
     50 
     51     else
     52 
     53     {
     54 
     55       ret = 0;
     56 
     57     }
     58 
     59    
     60 
     61     return ret;
     62 
     63 }
     64 
     65  
     66 
     67 int main(int argc,char* argv[], char* env[])
     68 
     69 {
     70 
     71    
     72 
     73     char*p =(char*)malloc(5);
     74 
     75  
     76 
     77     printf("%p
    ", p);//重置前二维数组的内存地址
     78 
     79    
     80 
     81     //重置大小后二维数组的内存地址
     82 
     83     //因为重置后的内存地址可以是新的地址,所以这里
     84 
     85     //需传入p指针的地址,以便在reset函数内部改变p,让
     86 
     87     //p指向新的地址。
     88 
     89     if (reset(&p, 5, 3))
     90 
     91     {
     92 
     93         printf("%p
    ", p);
     94 
     95     }
     96 
     97    
     98 
     99     free(p);
    100 
    101     return 0;
    102 
    103 }

    2. 二维数组与二级指针 

    (1)二维数组内存中一维的方式排布

    (2)二维数据中的第一维是一维数组

    (3)二维数组中的第二维才是具体的值

    (4)二维数组数组名可看做常量指针

    【实例分析】遍历二维数组

     1 #include <stdio.h>
     2 
     3  
     4 
     5 //以一维数组的方式来遍历二维数组
     6 
     7 void printfArray(int a[],int size)
     8 
     9 {
    10 
    11     int i = 0;
    12 
    13    
    14 
    15     printf("printfArray:%d
    ",sizeof(a)); //退化为指针
    16 
    17  
    18 
    19     for(i=0; i<size; i++)
    20 
    21     {
    22 
    23         printf("%d
    ",a[i]);
    24 
    25     }
    26 
    27 }
    28 
    29  
    30 
    31 int main(int argc,char* argv[], char* env[])
    32 
    33 {
    34 
    35     int a[3][3] = {{0, 1, 2},{3, 4, 5},{6, 7, 8}};
    36 
    37     int* p = &a[0][0];//指向a[0][0]元素
    38 
    39    
    40 
    41     int i;
    42 
    43     int j;
    44 
    45  
    46 
    47     for(i = 0;i < 3; i++)
    48 
    49     {
    50 
    51         for(j = 0;j < 3;j++)
    52 
    53         {
    54 
    55             printf("%d, ",*(*(a + i) + j));//以指针方式访问元素
    56 
    57         }
    58 
    59        
    60 
    61         printf("
    ");
    62 
    63     }
    64 
    65  
    66 
    67     printf("
    ");
    68 
    69    
    70 
    71     printfArray(p,9);//以一维数组的方式访问二维数组
    72 
    73  
    74 
    75     return 0;
    76 
    77 }

    3. 数组名

    (1)一维数组名代表数组首元素的地址:int a[5];   a的类型为int*

    (2)二维数组名同样代表数组首元素的地址:如int a[3][5], a的类型为int(*)[5]

    二维数组 

    含义及类型

    取地址符(&)

    sizeof

    数组名:a

    二维数组名a指向数组首元素的地址,即第1行(a[0])的地址(注意,不是a[0][0]的地址)。因此,a被称为行指针,指向第1行元素(一维数组)的地址。这个元素的类型是int(*)[5](即一维数组)。所以a的类型为int(*)[5];a可以看作是行指针,

    ②a + 1表示第二行的指针,a + i表示第i + 1行的指针(也是int(*)[5]类型)……

    &a表示整个二维数组的地址,所以&a + 1指向这个二维数组最后一个元素的后面。

     

    ①sizeof(a)表示整个二维数组的大小。

    ②sizeof(&a)为指针大小4字节。

    ③sizeof(*&a)等于sizeof(a)

    a[i]

    ①a[i]的类型:如果把二维数组看作是由三个元素(一维数组)组成的数组,那么这三个一维数组的数组名分别为a[0]、a[1]、a[2]。因此,a[0]可以看作是指向第1行(一维数组)首元素(a[0][0])的地址,a[i]是指向第i + 1行(一维数组)首元素的地址,所以a[i]为int*型

    ②a[i] + 1表示这行数组第2个元素的地址,即a[i] + 1是指向a[i][1]元素的地址,*(a[i] + 1)是a[i][1]元素的值。同理,a[i] + j是指向a[i][j]的地址,*(a[i] + j)是a[i][j]的值。

    &a[i]表示第i + 1行这行整个一维数组的地址。因此,&a[i] + 1是指向这行数组的下一行的指针。

    ①sizeof(a[i]):a[i]是一个一维数组。sizeof(a[i])为这个数组的大小。

    ②sizeof(&a[i])为指针大小4字节。

    ③sizeof(*&a[i])等于sizeof(a[i])

    a[i][j]

    与a、a[i]类型的含义不同,a[i][j]不再是一个指针,而是元素的类型,即int

    &a[i][j]表示这个元素的地址,即int*型

    ①sizeof(a[i][j]):a[i][j]表示元素的类型。

    ②sizeof(&a[i][j])为指针大小。

    ③sizeof(*&a[i][j])等于sizeof(a[i][j])

    备注

    ①通常情况下,数组名可看作是首元素的地址,而表格中所说的数组名a、a[i]的类型是指当他们代表各自数组的首元素时的类型。

    ②但当对数组名取地址符(&)或sizeof时,它不能看作是首元素的地址,而代表的是整个数组。请注意表格中&和sizeof两列的分析。

    【实例分析】数组的信息

    #include <stdio.h>
    
     
    
    int main(int argc,char* argv[], char* env[])
    
    {
    
       
    
        int a[3][5] = {0};
    
        int c;
    
       
    
        printf("Information for array:a[3][5]:
    ");
    
        printf("a = 0x%08X, a + 1 = 0x%08X, sizeof(a) = %d
    ", a, a + 1, sizeof(a));
    
        printf("&a = 0x%08X, &a + 1 = 0x%08X, sizeof(&a) = %d, sizeof(*&a) = %d
    ",
    
                   &a, &a + 1, sizeof(&a),sizeof(*&a));
    
     
    
        printf("
    ");
    
    
        //a[i]指向一个一维数组的首元素,a[i]+1指向该行第2个元素。sizeof(a[i])时不能看成首元素,而是这行整个一维数组
    
        for(c=0;c< 5;c++)
    
        {
    
          printf("a[%d] = 0x%08X, a[%d] + 1 = 0x%08X, sizeof(a[%d]) = %d,
    ",
    
                    c, a[c], c, a[c] + 1,c, sizeof(a[c]));
    
        }
    
     
    
        printf("
    ");
    
    
        //对a[i]进行&取地址符时,a[i]不能看作这一行的首元素,而是整个一维数组。即&a[i]表示第i+1的整个数组
        //&a[i]+1表示下一行。
    
    for(c=0;c< 5;c++)
    
        {
    
          printf("&a[%d] = 0x%08X, &a[%d] + 1 = 0x%08X, sizeof(&a[%d]) = %d, sizeof(*&a[%d]) = %d
    ",
    
                   c, &a[c],c, &a[c] + 1,c, sizeof(&a[c]), c, sizeof(*&a[c]));
    
        }
    
     
    
        return 0;
    
    }
    
    

    /*

    输出结果:

    Information for array:a[3][5]:

    a = 0x0023FE80, a + 1 = 0x0023FE94, sizeof(a) = 60

    &a = 0x0023FE80, &a + 1 = 0x0023FEBC, sizeof(&a) = 4, sizeof(*&a) = 60

    a[0] = 0x0023FE80, a[0] + 1 = 0x0023FE84, sizeof(a[0]) = 20,

    a[1] = 0x0023FE94, a[1] + 1 = 0x0023FE98, sizeof(a[1]) = 20,

    a[2] = 0x0023FEA8, a[2] + 1 = 0x0023FEAC, sizeof(a[2]) = 20,

    a[3] = 0x0023FEBC, a[3] + 1 = 0x0023FEC0, sizeof(a[3]) = 20,

    a[4] = 0x0023FED0, a[4] + 1 = 0x0023FED4, sizeof(a[4]) = 20,

    &a[0] = 0x0023FE80, &a[0] + 1 = 0x0023FE94, sizeof(&a[0]) = 4, sizeof(*&a[0]) = 20

    &a[1] = 0x0023FE94, &a[1] + 1 = 0x0023FEA8, sizeof(&a[1]) = 4, sizeof(*&a[1]) = 20

    &a[2] = 0x0023FEA8, &a[2] + 1 = 0x0023FEBC, sizeof(&a[2]) = 4, sizeof(*&a[2]) = 20

    &a[3] = 0x0023FEBC, &a[3] + 1 = 0x0023FED0, sizeof(&a[3]) = 4, sizeof(*&a[3]) = 20

    &a[4] = 0x0023FED0, &a[4] + 1 = 0x0023FEE4, sizeof(&a[4]) = 4, sizeof(*&a[4]) = 20

    */

    (3)二维数元素的访问方式int a[i][j];

      ①a[i][j]

      ②*(*(a + i) + j);  //a + i是第i+1行首元素(一维数组)的地址,即保存一个一维数的地址,*(a + i)取出当中保存的一维数组地址。注意这也是一个地址,而*(a + i)+j表示在这个一维数组地址基础上加j的偏移处,然后*(*(a + I)+ j)取出该元素出来。

    【实例分析】如何动态申请二维数组

    #include <stdio.h>
    
    #include <malloc.h>
    
     
    
    int** malloc2d(int row,int col)
    
    {
    
        int** ret = NULL;
    
       
    
        if((row >0) && (col >0))
    
        {
    
            int* p = NULL;
    
     
    
            //先申请第一维数组,用于存放行指针
    
            ret = (int**)malloc(row * sizeof(int*));
    
     
    
            //再申请整个数组存储空间的大小,用于存放所有元素
    
            p = (int*)malloc(row * col * sizeof(int));
    
     
    
            //将数组空间分为二维
    
            if ((ret != NULL) && (p != NULL))
    
            {
    
                int i=0;
    
                for(i=0; i<row; i++)
    
                {
    
                    ret[i] = p + i*col;
    
                }
    
            }
    
            else
    
            {
    
                free(ret);
    
                free(p);
    
               
    
                ret = NULL;
    
            } 
    
        }
    
     
    
        return ret;
    
    }
    
     
    
    void free2d(int** p)
    
    {
    
        if(*p != NULL) //p指向二维数组
    
        {
    
            //*p指向p[0],而这里保存的即是
    
            //第1个元素的地址,也是整个数
    
            //组元素空间地址。
    
            free(*p);  //释放元素所占空间
    
        }
    
     
    
        free(p);//释放行指针所占空间
    
    }
    
     
    
    int main()
    
    {
    
        int** a = malloc2d(3, 3);
    
        int i = 0;
    
        int j = 0;
    
     
    
        for(i=0; i<3; i++)
    
        {
    
            for(j=0; j<3; j++)
    
            {
    
                printf("%d, ",a[i][j]);
    
            }
    
            printf("
    ");
    
        }
    
     
    
        free2d(a);
    
     
    
        return 0;
    
    }

    【实例分析】无法将指针变量本身传递给一个函数,须传递指针的地址

    #include <stdio.h>
    
    #include <malloc.h>
    
    #include <string.h>
    
     
    
    void GetMemory(char* p,int num)
    
    {
    
        //由于p是函数参数,当函数返回时,会被释放
    
        p = (char*)malloc(num*sizeof(char));
    
    }
    
     
    
    void GetMemoryEx(char** p,int num)
    
    {
    
        //p指向一个指针,将该指针的值指向新的开辟的内存空间。
    
        *p = (char*)malloc(num * sizeof(char));
    
    }
    
     
    
    int main()
    
    {
    
        char* str = NULL;
    
       
    
    /*
    
        //错误的做法
    
        GetMemory(str,10);//试图让str让指向新开辟的内存空间。因为须改变
    
                          //指针str的值,所以得传递指针的地址过去。否则
    
                          //在传参时,GetMemory只是复制str的值过去。即,
    
                          //将NULL复制给参数。
    
       
    
        strcpy(str,"hello");
    
     
    
        free(str);//free并没有起作用,内存泄漏
    
    */
    
     
    
        //正确的做法
    
        GetMemoryEx(&str,10);//将str指针的地址传递到函数里,函数内部就
    
                             //可以改变str指针的值,让其指向新的地址。
    
       
    
        strcpy(str,"hello");
    
     
    
        free(str);//free并没有起作用,内存泄漏
    
     
    
        return 0;
    
    }

    4. 小结

    (1)C语言只支持一维数组

    (2)C语言中的数组大小必须在编译期就作为常数确定

    (3)C语言中的数组元素可以是任何类型的数据

    (4)C语言中的数组的元素可以是另一个数组

  • 相关阅读:
    visual studio项目多级引用不拷贝dll的问题
    ef6 code first,对已有数据库如何执行迁移
    wsl 修改默认安装路径
    Windows docker镜像文件无法删除
    Docker镜像下载很慢,各种加速无效
    activemq整合springboot使用(个人微信小程序用)
    angular入门一之环境安装及项目创建
    jquery中attr()和prop()的区别
    IntelliJ IDEA部署web项目,Tomcat没有出现Artifacts
    IntelliJ IDEA:创建Java Web工程
  • 原文地址:https://www.cnblogs.com/hoiday/p/10074012.html
Copyright © 2020-2023  润新知