C 温故知新 之 指针:数组指针、字符串指针、函数指针

一、数组指针  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++]=ifor(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<m;i++){j=n-1-i;temp=x[i];x[i]=x[j];x[j]=temp; } 
}

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


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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/449817.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql 查找配置文件 my.ini 位置方法

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 个人备注&#xff1a;不显示文件类型时&#xff0c;my.ini 文件名就叫作 my&#xff0c; 文件属性才显示 ini。 找到 my 文件看属性就知…

嵌入式操作系统内核原理和开发

嵌入式操作系统内核原理和开发&#xff08;开篇&#xff09; 操作系统是很多人每天必须打交道的东西&#xff0c;因为在你打开电脑的一刹那&#xff0c;随着bios自检结束&#xff0c;你的windows系统已经开始运行了。如果问大家操作系统是什么&#xff1f;可能有的人会说操作…

Java中对象比较

在Java之中不仅仅存在两个数字与两个字符串之间的比较&#xff0c;还存在两个对象之间的比较。 众所周知&#xff0c;两个数字之间的比较我们使用“”&#xff0c;两个字符串之间的比较我们使用“equals()”&#xff0c;那么两个对象之间如何进行比较呢&#xff1f;既然要进行两…

如何安装pfbprophet

最近facebook出来了一个软件包&#xff0c;可以用于时序数据预测&#xff0c;但是安装上&#xff0c;遇到问题不小&#xff0c;本人也在安装中遇到大大小小各种问题&#xff0c;然后查了各种资料&#xff0c;进行研究&#xff0c;终于找到一个最简单的办法。 不废话&#xff0…

JeeSite 4.0 (1.0)开发环境部署运行

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 环境要求 1、Java SDK 1.8 下载 2、Eclipse IDE for Java EE Mars 2 (4.5.2) 下载&#xff08;依Eclipse举例&#xff0c;IDEA雷同。&…

dojo 七 DOM dojo/dom

官方教程&#xff1a;Dojo DOM Functions对dom的使用&#xff0c;需要引用包dojo/dom。1.获取节点&#xff0c;dom.byIdbyId中既可以传递一个字符串&#xff0c;也可以传递一个节点对象 require(["dojo/dom", "dojo/domReady!"], function(dom) {function …

quantaxis中使用docker安装,出现的问题

本人在使用docker安装quantaxis时&#xff0c;经常发生docker报错&#xff0c;原因是与 wsl2冲突。之前不知道原因&#xff0c;直接就是卸载重装&#xff0c;累死我了。现在知道后&#xff0c;将解决方案记下&#xff0c;帮助后来者继续前行。 管理员打开cmd&#xff0c;输入 …

并发编程(多进程1)

一 multiprocessing模块介绍 python中的多线程无法利用多核优势&#xff0c;如果想要充分地使用多核CPU的资源&#xff08;os.cpu_count()查看&#xff09;&#xff0c;在python中大部分情况需要使用多进程。Python提供了multiprocessing。 multiprocessing模块用来开启子进…

LInux 下文件包的使用

1 .deb   http://wiki.ubuntu.org.cn/MySQL%E5%AE%89%E8%A3%85%E6%8C%87%E5%8D%97 2 .rpm

@RequiresPermissions 注解说明

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 RequiresAuthentication 验证用户是否登录&#xff0c;等同于方法subject.isAuthenticated() 结果为true时。 RequiresUser 验证用户…

千位分隔符转换为数字

最近下载了akshare里面的数据&#xff0c;然后发现有些数据格式为1,300这种格式&#xff0c;为str格式&#xff0c;但是又无法直接强制转换之类方式&#xff0c;特地寻求答案&#xff0c;并做笔记&#xff0c;留待自己与后来者一起避坑。 from locale import * atof(123,456)…

一本通1629聪明的燕姿

1629&#xff1a;聪明的燕姿 时间限制: 1000 ms 内存限制: 524288 KB【题目描述】 城市中人们总是拿着号码牌&#xff0c;不停寻找&#xff0c;不断匹配&#xff0c;可是谁也不知道自己等的那个人是谁。 可是燕姿不一样&#xff0c;燕姿知道自己等的人是谁&#xff0c;…

IT职场人生系列之二十四:程序员如何增加收入

这是IT职场人生系列的第二十四篇。&#xff08;序言&#xff0c;专栏目录&#xff09; 程序员的收入是广受关注的问题&#xff0c;很多人从业3&#xff5e;5年之后就会遇到这个收入瓶颈。尽管物价不断上涨&#xff0c;程序员尤其是初、中级程序员的收入不升反降。即使上次在某…

ASP 代码当前记录集不支持更新问题的解决办法。

错误类型&#xff1a;ADODB.Recordset (0x800A0CB3)当前记录集不支持更新。这可能是提供程序的限制&#xff0c;也可能是选定锁定类型的限制。 /Model/manage/Admin_Admin.asp, 第 35 行 找到放在数据库文件的--- 右键--》属性---》安全----》添加IIS来宾用户---》权限为&#…

@PathVariable 注解 说明

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 PathVariable 映射 URL 绑定的占位符 带占位符的 URL 是 Spring3.0 新增的功能&#xff0c;该功能在SpringMVC 向 REST 目标挺进发展过…

数据清洗,筛选

本人在私募&#xff0c;负责数据收集以及清洗&#xff0c;就是包括收集数据&#xff0c;按照领导要求&#xff0c;选出满足条件的数据&#xff0c;用于校验策略是否正确。 现在就在这进行代码上传&#xff0c;即用于自己总结整理&#xff0c;也用于供大家学习了解&#xff0c;实…

JS媒体查询

样式的改变使用C3的媒体查询 行为和功能的改变使用JS的媒体查询 matchMedia()方法参数可写任何一个CSSmedia规则&#xff0c;返回的是新的MediaQueryList对象&#xff0c;该对象有两个属性 media&#xff1a;查询语句的内容matches&#xff1a;检查查询结果&#xff0c;返回boo…

Ruby初步介绍

Ruby是脚本语言,与传统的C, Java不同的是,它不需要经过编译,而是直接可以被执行 Ubuntu下执行第一个ruby脚本 print("Hello David, This is your first Ruby script.\n") davidubuntu:~/RubyTrain/Basic$ ruby Hello.rb 运行结果: Hello David, This is your first R…

C/C++ main用法总结

今天看到一篇很好的文章&#xff0c;详细的讲解了C、C中的main函数&#xff0c;以及returne的用法。转载过来大家一起分享下。转自&#xff1a;http://www.cnblogs.com/ct6816678/archive/2012/10/26/2741824.htmlreturn是C预定义的语句&#xff0c;当return语句提供了一个值时…

如何将数据写入excel中,而不覆盖原有数据

之前直接用pandas库&#xff0c;然后to_excel&#xff08;&#xff09;&#xff0c;结果直接将原始数据直接覆盖&#xff0c;幸亏有备份。&#xff08;友善提醒&#xff0c;做数据处理之前&#xff0c;先将数据本地备份一份&#xff0c;确认完全没有问题&#xff0c;然后还是备…