zoukankan      html  css  js  c++  java
  • 数组指针与指针数组

    详解C语言中的数组指针与指针数组

    ·详解数组指针与指针数组

    ·数组指针

    一、区分

    首先我们需要了解什么是数组指针以及什么是指针数组,如下图:

    1.  
      int *p[5];
    2.  
      int (*p)[5];

    数组指针的意思即为通过指针引用数组,p先和*结合,说明了p是一个指针变量,指向一个大小为5的数组。所以,int (*p)[5]即为一个数组指针。int *p[5]则是一个大小为5且存放整型指针的数组。

    二、数组元素的指针

    1.定义

    指针变量既然可以指向变量,同样的,也能指向数组元素,因此,数组元素的指针就是数组元素的地址。

    它的写法为:

    1.  
      int *p=arr;
    2.  
      int *p=&a[0];

    这边我们需要再次明确,数组名并不代表整个数组,只是代表数组首元素的地址,因此上面两个语句是一样的。

    2.运算

    由于指针指向的是一个地址,因此数组指针也同样可以进行相关运算;例如指针的加减可以实现指针指向数组上一个或者下一个元素的功能。这边需要说明,数组指针中进行乘法和除法是没有意义的。

    如下图所示:

    在定义指针变量的时候需要定义类型,如果指针p指向了一个数组中的一个元素,那么p+1并不是将地址加上1,而是系统判定类型之后加上一个数组元素所占用的字节数(即为p+1*d)。

    3.通过指针引用数组元素

    代码如下图:

    1.  
      #include<stdio.h>
    2.  
      int main()
    3.  
      {
    4.  
      int a[10]={1,2,3,4,5,6,7,8,9,0};
    5.  
      int *p;
    6.  
      for(p=a ; p<(a+10) ; p++)
    7.  
      {
    8.  
      printf("%d ",*p);
    9.  
      }
    10.  
      printf(" ");
    11.  
      return 0;
    12.  
      }

    先让指针p指向a数组的首元素,打印*p(即指向数组的值),然后执行p++,使得p指向下一个元素,直到输出数组的十个元素为止。

    三、通过指针引用多维数组

    1.多维数组元素的地址

    我们以二维数组为例,首先需要明确一点的是二维数组的首元素地址并非一个单个元素,而是首行的地址,如下图:

    下面我们列出相关地址的表示方式:

    表示形式 含义
    a     二维数组名,指向a[0]
    a[0], *(a+0), *a 0行0列元素地址
    a+1, &a[1] 1行首地址
    a[1], *(a+1) a[1][0]的地址
    a[1]+2, *(a+1)+2, &a[1][2]

    a[1][2]的地址

    *(a[1]+2), *(*(a+1)+2), a[1][2] a[1][2]的值

    上图都是二维数组中地址的不同表示形式。

    2.指向多维数组的指针变量

     

    输出每一个值依然可以像一维数组一样,但这里我们可以介绍一种新的方法:

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

    int (*p)[12];(错误点)

    int i=0;

    p=&a;(错误点)

    printf("%d ",(*p)[11]);

    return 0;

    }

     
    int main()
    {

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

    int (*p)[4];(纠正点)

    int i=0;

    p=a;(纠正点)

    printf("%d ",(*p)[11]);

    return 0;

    }

    
    
    
    

    就像我们前面的例子一样,int(*p)[12]表示定义一个指针变量,它指向一个包含12个整型元素的一堆数组。我们将其设定为12便可以存下整个a数组,当然也可以存一行4个,最后如果输出的话就方便了许多。

    四、数组指针作函数参数

    下面是几种传参的方式:

    1.  
      void test()
    2.  
      {
    3.  
      int arr[3][5] = {0};
    4.  
      print(arr);
    5.  
      }
    6.  
      void print(int arr[3][5])
    7.  
      {}
    8.  
      void print(int arr[][5])
    9.  
      {}
    10.  
      void print(int **arr)
    11.  
      {}
    12.  
      void print(int (*arr)[5])
    13.  
      {}

    我们可以看出第三种方式明显是不行的,这边引用了一个二级指针,但是我们上面提到过数组的地址应该放到数组指针中去。而第四种方法就是我们上面提到过的,而这种方式是可行的。

    下面是一个一级指针传参的例子:

    1.  
      #include <stdio.h>
    2.  
      void print(int *p, int sz)
    3.  
      {
    4.  
      int i = 0;
    5.  
      for(i=0; i<sz; i++)
    6.  
      {
    7.  
      printf("%d ", *(p+i));
    8.  
      }
    9.  
      }
    10.  
      int main()
    11.  
      {
    12.  
      int arr[10] = {1,2,3,4,5,6,7,8,9};
    13.  
      int *p = arr;
    14.  
      int sz = sizeof(arr)/sizeof(arr[0]);
    15.  
      print(p, sz);
    16.  
      return 0;
    17.  
      }

    ·指针数组

    一、指针数组

    1.定义

    int *p[5];

    上面使我们刚开始举出的例子,这就是一个最简单的指针数组。因此我们可以得出指针数组的定义。指针数组:一个数组的元素均为指针类型数据,称为指针数组。

    假设我们定义一个数组,各个元素指向不同的字符串,如下图:

    上图所示,我们定义一个指针数组arr,然后把各字符串的地址赋给各个元素,即arr[0]和arr[1]。

    通过一个简单的函数就可以进行输出了。

    二、指向指针数据的指针

    首先我们可以定义一个指向指针数据的指针变量:

    char **p;
    

    为了方便我们理解,其实**p也就等于*(*p)。*p表示p为一个指针变量,前面的*表示*p指向的是char *类型的数据。换一句话来说,如果引用*p,就是得到p所指向的值,如果拿上面的例子来说就是字符串"Hello"和"World"。

    我们可以通过下面的代码来实现:

    1.  
      int main()
    2.  
      {
    3.  
      char *arr[]={"Hello","World"};
    4.  
      char **p;
    5.  
      int i;
    6.  
      for(i=0; i<2; i++)
    7.  
      {
    8.  
      p=arr+i;
    9.  
      printf("%s ",*p);
    10.  
      }
    11.  
      return 0;
    12.  
      }
      转发:https://blog.csdn.net/q302989778/article/details/80216899?utm_medium=distribute.pc_feed.none-task-blog-personrec_random_tag-14.nonecase&depth_1-utm_source=distribute.pc_feed.none-task-blog-personrec_random_tag-14.nonecase&request_id=5f61efc598fa0775e7c628cd
       
     
  • 相关阅读:
    如何用redis/memcache做Mysql缓存层?
    孤儿进程和僵尸进程总结
    二叉树的遍历(非递归)
    Linux进程分配内存的两种方式--brk() 和mmap()
    Hbase
    cgroup 分析之CPU和内存部分
    十道海量数据处理面试题与十个方法大总结
    快速定位性能瓶颈,检查出所有资源(CPU、内存、磁盘IO等)的利用率(utilization)、饱和度(saturation)和错误(error)度量,即USE方法
    红黑树
    tcp 两个重要窗口:滑动窗口 和 拥塞窗口
  • 原文地址:https://www.cnblogs.com/linyinmobayu/p/14261984.html
Copyright © 2011-2022 走看看