博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C 温故知新 之 指针:数组指针、字符串指针、函数指针
阅读量:6717 次
发布时间:2019-06-25

本文共 5481 字,大约阅读时间需要 18 分钟。

一、数组指针  1.指向数组元素的指针

  1、定义:  

    数组指针     :数组的起始地址

    数组元素指针:数组元素的地址

  2、定义一个指向数组元素的指针变量的方法,与之前介绍的指针变量相同。

    例如: 

         int a[10];   /*定义 a 为包含10 个整型数据的数组*/
         int *p;      /*定义p为指向整型变量的指针*/

  3、指针变量赋值:

    p=&a[0]; //或者:p=a; 原因是p,a,&a[0]均指向同一单元

    把 a[0]元素的地址赋给指针变量 p。也就是说,p指向 a 数组的第 0 号元素。

  4、格式

    类型说明符  *指针变量名;

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

 

看图识字:

  1、 p+i 和a+i 就是 a[i]的地址,或者说它们指向 a数组的第 i个元素。

  2、*(p+i)或*(a+i)就是p+i或a+i所指向的数组元素, 即a[i]。 例如, *(p+5)或*(a+5)就是a[5]。

  3、指向数组的指针变量也可以带下标,如 p[i]与*(p+i)等价。

根据以上叙述,引用一个数组元素可以用:

  1、下标法,即用 a[i]形式访问数组元素。
  2、指针法,即采用*(a+i)或*(p+i)形式,用间接访问的方法来访问数组元素,其中 a是数组名,p是指向数组的指针变量,其处值 p=a。

Eg:

  1、下标法:

  

                 

   2、通过数组名计算元素的地址

    

                

   3、指针变量指向元素

      

              

  注意的问题

    1、指针变量可以实现本身的值的改变。如 p++是合法的;而 a++是错误的。因为 a 是数组名,它是数组的首地址,是常量。

    2、要注意指针变量的当前值。请看下面的程序。

 

int a[10],i,*p;    p=a;//p=&a[0]    for(i=0;i<10;i++)        *p++=i; //a[i++]=i             for(i= 0;i<10;i++)        printf("a[%d]=%d\n",i,*p++);

 

你看看出问题吗?如果可以别忘了告诉我(虽然书上解释了“要注意指针变量的当前值”但是还是有点迷糊)

看看运行结果

    

         

 

正确的方法就是把上面注释的部分拿出来即可,看看结果:

  

       

 

 

 

 

3.数组名作函数参数

   数组名可以作函数的实参和形参

main() {
int array[10]; …… …… f(array,10); …… …… } f(int arr[],int n); { …… …… } array 为实参数组名,arr为形参数组名。

   Eg:将数组 a 中的 n 个整数按相反顺序存放。

    1、形参是数组名

main(){    //将数组 a 中的 n 个整数按相反顺序存放。     int i,a[10]={
3,7,9,11,0,6,7,5,4,2}; printf("The original array:\n"); for(i=0;i<10;i++) { printf("%d,",a[i]); } printf("\n"); inv(a,10); printf("The array has been inverted:\n"); for(i=0;i<10;i++) { printf("%d,",a[i]); } printf("\n");}/*形参是数组名*/ inv(int x[],int n){ int temp,i,j,m=(n-1)/2; for(i=0;i

    2、形参x为指针变量

/*形参x为指针变量*/ inv2(int *x,int n) {     int *p,temp,*i,*j,m=(n-1)/2;     i=x ;j=x+n-1;p=x+m;     for(;i<=p;i++,j--)     {        temp=*i;        *i=*j;        *j=temp;     }     return; }

  归纳总结:如果有一个实参数组,想在函数中改变此数组的元素的值,实参与形参的对应关系有以下4种:

    1、形参和实参都是数组名。

      main()                    f(int x[],int n) { ……}

      {int a[10]; 
        …… 
       f(a,10) 
        ……
      } 

    2、实用数组,形参用指针变量

      main()                      f(int *x,int n) {  …… }

      {int a[10];
        ……
       f(a,10) 
        ……
      }

    3、 实参、型参都用指针变量

    4、实参为指针变量,型参为数组名

4.指向多维数组的指针和指针变量

   1.  多维数组的地址 设有整型二维数组 a[3][4]如下:

     0   1   2   3 
         4   5   6   7
     8   9  10  11
  它的定义为:
    int a[3][4]={
{0,1,2,3},{4,5,6,7},{8,9,10,11}}

   C语言允许把一个二维数组分解为多个一维数组来处理,因此数组 a 可分解为三个一维数组,即 a[0],a[1],a[2]   

    

  例如 a[0]数组,含有 a[0][0],a[0][1],a[0][2],a[0][3]四个元素。

  a[0]是第一个一维数组的数组名和首地址,因此a,a[0],*(a+0),*a,&a[0][0]是相等的。

  Eg:

  

int a[3][4] ={
0,1,2,3,4,5,6,7,8,9,10,11}; //0,1,2,3 a[0]行 //4,5,6,7 a[1]行 //8,9,10,11 a[2]行 printf("0\n"); printf("%d\n",*(a+0)); printf("%d\n",a); printf("%d\n",*a); printf("%d\n",a[0]); printf("%d\n",&a[0]); printf("%d\n",&a[0][0]); printf("………………………………………………\n"); printf("1\n"); printf("%d\n",a+1); printf("%d\n",*(a+1)); printf("%d\n",a[1]); printf("%d\n",&a[1]); printf("%d\n",&a[1][0]); printf("………………………………………………\n"); printf("2\n"); printf("%d\n",a+2); printf("%d\n",*(a+2)); printf("%d\n",a[2]); printf("%d\n",&a[2]); printf("%d\n",&a[2][0]); printf("………………………………………………\n"); printf("3【a[1]行+1=>1244996+4】\n"); printf("%d\n",a[1]+1); printf("%d\n",*(a+1)+1); printf("………………………………………………\n"); printf("取2行值\n"); printf("%d,%d\n",*(a[1]+0),*(*(a+1)+0)); printf("%d,%d\n",*(a[1]+1),*(*(a+1)+1)); printf("%d,%d\n",*(a[1]+4),*(*(a+1)+4)); //越界继续向下取值8*/

 

  结果:

   

 

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

  把二维数组 a 分解为一维数组 a[0],a[1],a[2]之后,设 p 为指向二维数组的指针变量。可定义为: 
        int (*p)[4]
  它表示 p 是一个指针变量,它指向包含 4 个元素的一维数组。若指向第一个一维数组a[0],其值等于 a,a[0],或&a[0][0]等。而 p+i 则指向一维数组 a[i]。从前面的分析可得出*(p+i)+j是二维数组 i 行j 列的元素的地址,而*(*(p+i)+j)则是i行 j 列元素的值。

  二维数组指针变量说明的一般形式为:

    类型说明符  (*指针变量名)[长度]

  注意“(*指针变量名)”两边的括号不可少,如缺少括号则表示是指针数组

  eg:

main(){     int a[3][4]={
0,1,2,3,4,5,6,7,8,9,10,11}; int(*p)[4]; int i,j; p=a; for(i=0;i<3;i++) {
for(j=0;j<4;j++) printf("%2d ",*(*(p+i)+j)); printf("\n");} }

 

二、字符串指针 1、字符串的表示形式

   C 语言中,可以用两种方法访问一个字符串:

    1、用字符数组存放一个字符串,然后输出该字符串

    2、用字符串指针指向一个字符串

  

        

 

 

 

 

 2、 使用字符串指针变量与字符数组的区别

  1、字符串指针变量本身是一个变量,用于存放字符串的首地址,而字符串本身是存放在以该首地址为首的一块连续的内存空间中并以‘\0’作为串的结束

  2、对字符串指针方式 char *ps="C Language";

    可以写为: 

         char *ps;
      ps="C Language";
    而对数组方式: 
        static char st[]={"C Language"};
    不能写为: 
        char st[20]; 
        st={"C Language"}; 而只能对字符数组的各元素逐个赋值。

 

 三、函数指针    

   在C语言中,一个函数总是占用一段连续的内存区,而函数名就是该函数所占内存区的首地址。我们可以把函数的这个首地址(或称入口地址)赋予一个指针变量,使该指针变量指向该函数。然后通过指针变量就可以找到并调用这个函数。我们把这种指向函数的指针变量称为“函数指针变量”。

   函数指针变量定义的一般形式为:

     类型说明符  (*指针变量名)();

  其中“类型说明符”表示被指函数的返回值的类型。 “(* 指针变量名)”表示“*”后面的变量是定义的指针变量。最后的空括号表示指针变量所指的是一个函数。

  例如: 

      int (*pf)();

  Eg:

    

main(){        int comMax(int a,int b);    int (*pmax) ();//定义:类型说明符  (*指针变量名)(); 表示 pmax 是一个指向函数入口的指针变量,该函数的返回值(函数值)是整型。    int x,y,z;    pmax=comMax;    printf("input two numbers:\n");    scanf("%d%d",&x,&y);    z=(*pmax)(x,y);//调用函数的一般形式为:(*指针变量名) (实参表)  或者 comMax(x,y);    printf("max=%d",z);  }int comMax(int a,int b){    if(a>b) return a; else return b;}

  结果:

          

 

  从上述程序可以看出用,函数指针变量形式调用函数的步骤如下: 

    1、先定义函数指针变量,如后一程序中第 9 行 int (*pmax)();定义 pmax 为函数指针变量

    2、把被调函数的入口地址(函数名)赋予该函数指针变量,如程序中第 11 行 pmax=max;

    3、用函数指针变量形式调用函数,如程序第 14 行 z=(*pmax)(x,y);

    4、调用函数的一般形式为:

         (*指针变量名) (实参表)
      使用函数指针变量还应注意以下两点:

        a、函数指针变量不能进行算术运算,这是与数组指针变量不同的。数组指针变量加减一个整数可使指针移动指向后面或前面的数组元素,而函数指针的移动是毫无意义的  

        b、函数调用中"(*指针变量名)"的两边的括号不可少,其中的*不应该理解为求值运算,在此处它只是一种表示符号

作者:
出处:
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

你可能感兴趣的文章
(转载)Mac下使用Web服务器性能/压力测试工具webbench、ab、siege
查看>>
学生管理系统实例
查看>>
「造个轮子」——cicada(轻量级 WEB 框架)
查看>>
2-AIV--使用ContentProvider查询联系人
查看>>
1137. Final Grading (25)
查看>>
算法与数据结构(十) 总结
查看>>
这部在豆瓣和IMDb都曾得到高分的电影,让我震撼......
查看>>
Json解析框架之Gson详解
查看>>
支持生产阻塞的线程池
查看>>
[Hadoop]Reducer总是能复用为Combiner?
查看>>
自动化与机器人
查看>>
ESP8266 OTA之浏览器更新
查看>>
专访光鉴科技CEO朱力:打破苹果垄断,自研芯片打造低成本3D视觉解决方案
查看>>
docker的下载
查看>>
redis几种数据导出导入方式
查看>>
中间件万里行?不远万里来相会?| 阿里中间件Aliware 开启全国赋能之旅
查看>>
对抗思想与强化学习的碰撞-SeqGAN模型原理和代码解析
查看>>
多Git账户的Git使用
查看>>
iOS脚本自动编译静态包/静态库
查看>>
并发安全的 ConcurrentHashMap 实现原理详解
查看>>