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;既然要进行两…

并发编程(多进程1)

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

一本通1629聪明的燕姿

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

数据清洗,筛选

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

HSTS的来龙去脉

前言 安全经常说“云、管、端”&#xff0c;“管”指的是管道&#xff0c;传输过程中的安全。为了确保信息在网络传输层的安全&#xff0c;现在很多网站都开启了HTTPS&#xff0c;也就是HTTPTLS&#xff0c;在传输过程中对信息进行加密。HTTPS使用了对称加密、非对称加密、消息…

利用XShell上传、下载文件(使用sz与rz命令) 超实用!

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 rz、sz 安装方式&#xff1a;sz/rz命令安装方式 借助XShell&#xff0c;使用linux命令sz可以很方便的将服务器上的文件下载到本地&#…

quantaxis使用docker安装,解决了一个很奇特的问题

之前使用docker-compose pull 更新之后&#xff0c;使用docker-compose up进行安装。出现 qaweb显示address already in web,cmd中显示Starting qa_web is wrong。之前一直觉得什么毛病啊&#xff0c;试了很多办法。 比如关闭8010接口&#xff1a; netstat -ano|findstr “801…

Datawhale MySQL 训练营 Task2 查询语句

目录 MySQL 管理MySQL 用户管理 参考数据库管理SQ查询语句1. 导入示例数据库&#xff0c;教程 MySQL导入示例数据库2. 查询语句 SELECT3. 筛选语句 WHERE &#xff0c;过滤4. 分组语句 GROUP BY5. 排序语句 ORDER BY6. 函数作业总结MySQL 管理 MySQL版本 8.0.15 MySQL 用户管理…

视差滚动(Parallax Scrolling)插件补充

13. Windows Windows (github) 是一个让你用占据整个屏幕的section来构建单面网站的插件。该插件提供给你一些回调函数&#xff0c;当新的section出现在可视区并且并且处理快照时被调用&#xff0c;所以你可以轻松的继承它来自定义导航菜单或更多的东西。下面是一个例子&#x…

MVC日期格式化,后台使用Newtonsoft.Json序列化日期,前端使用”f”格式化日期

MVC控制器中&#xff0c;经常使用Newtonsoft.Json把对象序列化成json字符串传递到前端视图。当对象中有DateTime类型的属性时&#xff0c;前后台如何处理才能把DateTime类型转换成想要的格式呢&#xff1f; 有这样的一个类具有DateTime类型属性&#xff1a; using System; name…

Google Go Programming In Eclipse

http://www.tutorialsavvy.com/2013/04/google-go-programming-in-eclipse.html/ Google Go Programming In Eclipse The new “Go” programming language is from Google co.It has many features better then other languages.Go language features are:-– High Speed Comp…

pycharm打开ipynb显示为文本格式解决办法

然后进入 添加类型 jupyter notebook 然后下方添加 *.ipynb

[基础篇]ESP32-RTOS-SDK教程(一)之Windows环境搭建

当下正是物联网最好的时代&#xff0c;学习新的技术怎么能只学习ESP8266呢&#xff1f;要知道ESP8266还有一个孪生兄弟呢&#xff0c;最重要的是这个孪生兄弟要比ESP8266是更厉害的&#xff0c;所以我们也是非常有必要学习一下的&#xff0c;其实这篇文章去年就已经写了&#x…

安卓系统上的远程 JS 调试 Remote JavaScript Debugging on Android

每当在 Android 移动设备上调试网页时&#xff0c;开发人员往往都会不自觉陷入调试的泥潭中去。《Android开发指南》提供了一个解决方案&#xff0c;却有点繁琐复杂。因此&#xff0c;许多 Web 开发人员会倾向于使用类似 Firefox Firebug 的或像 WebKit 的 Web Inspector 之类的…

SEO艺术

SEO艺术 编辑推荐 在本书中&#xff0c;四位搜索引擎优化&#xff08;SEO&#xff09;领域最受瞩目的专家阐述了制订以及执行一个完善的SEO策略时应遵循的一些实用指南与最新技术。 基本信息 原书名&#xff1a; The Art of SEO原出版社&#xff1a; OReilly作者&#xff1a; (…

http状态码301和302详解及区别

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 一直对http状态码301和302的理解比较模糊&#xff0c;在遇到实际的问题和翻阅各种资料了解后&#xff0c;算是有了一定的理解。这里记录下…

哪些编程语言需要修复?

摘要&#xff1a;编程语言有十全十美的吗&#xff1f;每种语言都有缺陷吗&#xff1f;这不&#xff0c;Java、C、C、Python都中枪了。语言之间也可相互“掐架”&#xff0c;一起来看下。 原文作者Kevin Kelleher采用一种比较新颖的方式来比较编程语言&#xff1a;即描述每个编程…

Python标准库

《Python标准库》基本信息原书名&#xff1a; The Python Standard Library by Example 原出版社&#xff1a; Pearson Education 作者&#xff1a; (美)Doug Hellmann 译者&#xff1a; 刘炽 出版社&#xff1a;机械工业出版社 ISBN&#xff1a;9787111378105上架时间&#xf…