zoukankan      html  css  js  c++  java
  • C语言学习笔记--多维数组和多维指针

    1. 指向指针的指针

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

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

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

    重置动态空间的大小

    #include <stdio.h>
    #include <malloc.h>
    
    int reset(char**p,int size,int new_size)
    {
        int ret = 1;
        int i = 0;
        int len = 0;
        char* pt = NULL;
        char* pp = *p;
    
        if((p != NULL)&&(new_size > 0))
        {
            pt = (char*)malloc(new_size);
            
            len = (size < new_size)?size : new_size;//取较小者
            
            //复制原内容
            for(i=0; i<len;i++){
                *pt = *pp++;
            }
            
            free(*p); //释放原空间
            *p = pt;  //*p指针指向新空间
        }
        else
        {
          ret = 0;
        }
        
        return ret;
    }
    
    int main(int argc,char* argv[], char* env[])
    {
        
        char*p =(char*)malloc(5);
    
        printf("%p
    ", p);//重置前二维数组的内存地址
        
        //重置大小后二维数组的内存地址
        //因为重置后的内存地址可以是新的地址,所以这里
        //需传入p指针的地址,以便在reset函数内部改变p,让
        //p指向新的地址。
        if (reset(&p, 5, 3))
        { 
            printf("%p
    ", p);
        }
        
        free(p);
        return 0;
    }

    2.二维数组与二级指针

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

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

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

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

    #include <stdio.h>
    
    //以一维数组的方式来遍历二维数组
    void printfArray(int a[],int size)
    {
        int i = 0;
        
        printf("printfArray:%d
    ",sizeof(a)); //退化为指针
    
        for(i=0; i<size; i++)
        {
            printf("%d
    ",a[i]);
        }
    }
    
    int main(int argc,char* argv[], char* env[])
    {
        int a[3][3] = {{0, 1, 2},{3, 4, 5},{6, 7, 8}};
        int* p = &a[0][0];//指向a[0][0]元素
        
        int i;
        int j;
    
        for(i = 0;i < 3; i++)
        {
            for(j = 0;j < 3;j++)
            {
                printf("%d, ",*(*(a + i) + j));//以指针方式访问元素
            }
            
            printf("
    ");
        }
    
        printf("
    ");
        
        printfArray(p,9);//以一维数组的方式访问二维数组
    
        return 0;
    }

    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;
    }

    参考资料:
    www.dt4sw.com
    http://www.cnblogs.com/5iedu/category/804081.html 

  • 相关阅读:
    [原]RHCS集群的服务切换测试札记
    [原]从Clustering Factor说起
    命令行下设置IP地址的方法
    [原]SQL Server 2005 链接服务器使用一例
    [原]Oracle删除大表并回收空间的过程
    [转]从沙子到芯片:且看处理器是怎样炼成的
    [原] 在域环境中打开SSMS非常慢
    [原]将特定格式的string转换为DateTime
    [原] 在域环境中打开SSMS非常慢 续
    [转]Linux 下判断Server 内存是否不足
  • 原文地址:https://www.cnblogs.com/CoderTian/p/5907933.html
Copyright © 2011-2022 走看看