指针、数组、指针数组、数组指针

一维数组和一级指针变量

  1. 数组名是一个地址,可以使用一个一级指针变量接收其地址;
    int arr[5];
    int p = arr;
    
  2. 两者不同的是数组名是一个常量,不能被赋值,也就是数组名不能单独出现在赋值号的左边;
    int arr[5], b[10], c;
    arr = b;     //错误,数组名不能被赋值
    arr = &c     //错误,数组名不能被赋值
    
  3. 数组和指针的越界访问编译器都不会报错;
    int arr[5];
    int *p = arr;
    printf("*(p - 1) = %d\n", *(p - 1));//打印arr[-1]的值
    printf("a[-1] = %d\n", arr[-1]);     //打印arr[-1]的值
    //系统不会报错,但是打印出来的却是垃圾值
    
  4. 在使用指针时,一定不要使用野指针,使用野指针时将会产生不可预知的错误;在不使用的时候可以将其指向NULL,而NULL时不允许用户使用的,当我们访问NULL时,将会产生段错误,段错误比不可预知的错误好的多,至少你知道有错了;
    int *p;
    printf("*p = %d",*p);    //打印出来一个垃圾值,操纵野指针将会导致未知的错误
    
    int *p = NULL;
    printf("*p = %d", *p);    //段错误
    
  5. 指针可以使用指针名[index]访问,数组也可通过*(数组名 + index)访问。
     int arr[5] = {0, 1, 2, 3, 4};
     int *p = arr;
     printf("arr[1] = %d\n", arr[1]);        //arr[1] = 1
     printf("*(arr + 1) = %d\n", *(arr + 1));        //*(arr + 1) = 1
     printf("*(p + 1) = %d\n", *(p + 1));        //*(p + 1) = 1
     printf("p[1] = %d\n", p[1]);        //p[1] = 1
    

二维数组和二级指针

  1. 二维数组的数组名二维数组名不是二级指针,而是一个数组指针;使用普通的一级指针保存二维数组的首地址,即便能保存也没法按行操作;
    int arr[10][10];
    int *p = arr;     //因为同一操作系统中,指针的存储空间大小相同,可以保存下二维数组的首地址,但是有些编译器会报错,类型不匹配
    
  2. 二级指针指向一级指针的指针,二级指针指向一个指针数组是合法的,其值就是指针数组第一个元素的地址,用二级指针指向指针数组是合法的,但是直接使用二级指针指向二维数组就会报错。
    int arr[10][10];
    int **p = arr;
    int **q = &arr[0];
    int **k = &arr;
    //上面三者在编译的时候都会报错
    

一级指针和二级指针

  1. 二级指针是一级指针的升维,可以通过二级指针修改一级指针的值;
  2. 可以通过一级指针修改普通变量的值;
    int a = 10;
    int b = 20;
    int *p = &a;
    int **q = &p;   //取地址相当于升维
    *p = 30;    //将a的值修改为20
    *q = &b;    //p指向b
    **q = 40;   //将b的值修改为40
  1. 在函数传参时,将一维指针当作实参直接传递给函数,实际上传递的是指针所指向的地址,可以修改指针指向的空间的内容;在改变形参的指向不会影响实参的指向;
    void func(int *p){
         *p = 20;        //将p指向空间的内容修改为20
         p = NULL;       //修改p的指向为NULL
    }
    
    int a = 10;
    int *p = &a;
    func(p);
    printf("a = %d\n", a); //a = 20,通过swap函数修改了a的值
    printf("*p = %d\n", *p); //*p = 20,在函数中修改指针的指向,并没有影响实参的指向,属于值传参
    
  2. 想要在函数中修改一级指针的指向,那么就需要通过二级指针来操作;
    void func(int **q){
         **q = 20;        //将p指向空间的内容修改为20
         *q = NULL;       //修改p的指向为NULL
    }
    
    int a = 10;
    int *p = &a;
    func(&p);
    printf("a = %d\n", a); //a = 20,通过swap函数修改了a的值
    printf("*p = %d\n", *p); //段错误,非法访问内存NULL
    

指针数组和数组指针

  1. 指针数组的本质是数组,只不过数组中每个元素都是一个指针,定义一个指针数组
    int *p[10];     //定义了一个具有10元素的指针数组
    
  2. 数组指针的本质是一个指针,其指向具有相同列元素的数组
    int (*p)[10];   //定义了一个指向10个列元素的数组指针
    

指针数组、数组指针、二级指针、二维数组

  1. 对于一个二维数组,其数组名相当于一个行指针,可以使用一个数组指针指向它,并通过数组指针来操作二维数组;
    int arr[3][4] = {1,2,3,4,\
     				5,6,7,8,\
     				9,10,11,12};
    
     //定义一个数组指针指向二维数组
     int (*p)[4] = NULL;
    p = arr;
    
     //数组指针指向二维数组后 有下面的等价关系
     //arr[i] <==> *(arr+i) <==> p[i] <==> *(p+i)  
     //arr[i][j] <==> *(arr[i]+j) <==> *(*(arr+i)+j)  <==   \
       ==> p[i][j] <==> *(p[i]+j) <==> *(*(p+i)+j)
    
  2. 指针数组中的每个元素可以指向二维数组中的对应行,这样就可以通过操作指针数组来操作二维数组,一般多用于函数传参传二维组时使用;
    //使用指针数组来接收传来的二维数组
    void print_array(int (*p)[4], int line, int col){
        for(int i = 0; i < line; i++){
     	   for(j = 0; j < col; j++){
     		   printf("%d  ", p[i][j]);
     	   }
     	   printf("\n");
        }
    }
    
    int arr[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
    print_array(arr, 3, 4);//遍历输出二维数组
    
  3. 使用二维数组存储不定长度的字符串时会照成空间的浪费,特别是字符串长度差异较大时;使用指针数组处理这种问题特别合适,数组中的每个元素可以指向一个字符串,这样就提升了空间的利用率;
    //可以将多个字符串存储在二维数组中,但会造成空间上的严重浪费
    char name1[3][64] = {"zhangsan",
     					"fulajimier.fulajimiluoweiqi.pujing",
     					"wangwu"};
    
    //定义了一个指针数组,数组名叫 name2  **数组中有3个元素**
     //每个元素都是一个  char * 类型的指针
     char *name2[3] = {NULL, NULL, NULL};
     name2[0] = "zhangsan";
     name2[1] = "fulajimier.fulajimiluoweiqi.pujing";
     name2[2] = "wangwu";
    
  4. 当指针的类型相同时,+1移动的大小也相同时,我们可以认为二级指针和二维数组时等价的。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值