指针应用场景一:交换两个变量的值

  在学习函数时,交换两个数的值,做一个swap函数,传递值进去,也可以将两个值交换过来,没问题,可是离开swap就没有用了,为什么?因为传进去的是两个值。

  1. #include <stdio.h>
  2. void swap(int a,int b);
  3.  
  4. int main(void) {
  5. int i=;
  6. int j=;
  7. swap(i,j);
  8. printf("i=%d,j=%d\n",i,j);
  9. return ;
  10. }
  11.  
  12. void swap(int a,int b){
  13. int p;
  14. p=a;
  15. a=b;
  16. b=p;
  17. printf("a=%d,b=%d\n",a,b);
  18. }

  现在学过指针后,就可以用指针来交换变量了,传两个地址进去,试一下:

  1. #include <stdio.h>
  2. void swap(int *pa,int *pb);
  3.  
  4. int main(void) {
  5. int a=;
  6. int b=;
  7. swap(&a,&b);
  8. printf("a=%d,b=%d\n",a,b);
  9. return ;
  10. }
  11.  
  12. void swap(int *pa,int *pb){
  13. int t;
  14. t=*pa;
  15. *pa=*pb;
  16. *pb=t;
  17. }

  swap函数的参数是两个指针,在swap内部使用的都是*运算符,在main里将a,b的地址传递过去,运行我们发现值交换成功了。

指针应用场景二:函数通过指针返回多个值

  在上面的例子中,swap函数在做交换后,返回来2个值,只返回a不够,还应该返回b。所以某些值就只能通过指针带回,也就是说传入的参数实际上是需要保存带回的结果的变量。再看一个例子:

  1. #include <stdio.h>
  2. void minmax(int a[],int len,int *max,int *min);
  3.  
  4. int main(void) {
  5. int a[]={,,,,,,,,,,,,,,,,};
  6. int min,max;
  7. minmax(a,sizeof(a)/sizeof(a[]),&min,&max);
  8. printf("min=%d,max=%d\n",min,max);
  9. return ;
  10. }
  11.  
  12. void minmax(int a[],int len,int *min,int *max){
  13. int i;
  14. *min =*max=a[];
  15. for(i=;i<len;i++){
  16. if(a[i]<*min){
  17. *min=a[i];
  18. }
  19. if(a[i]>*max){
  20. *max=a[i];
  21. }
  22. }
  23. }

  minmax函数有4个参数,第一个参数a[]是数组,在这个参数中找出最大和最小的数组元素,第二个len是表示数组的长度,最后两个是*max和*min,minmax函数需要算出两个结果,最小值和最大值。两个结果不可能通过函数的返回值来获得,返回值只能返回一个,那么需要通过两个指针来返回两个结果。

  在minmax函数中,首先使*min和*max等于a的第一个元素。然后使用for循环从第二个元素起遍历整个数组,如果发现某个元素比*min小了,就将该值赋值给*min。最后在main里调用minmax函数,使用sizeof函数得到数组的长度传递过去,然后将main里的int类型min和max取地址传递给minmax函数。查看下运行的结果,min是1,max是55.

  这就是指针应用非常常见的一个场景,需要函数处理的结果不止一个,通过指针把要接受结果的变量的地址传递过去,然后在函数内部把这些变量的值填好,同时传递回来。所以虽然*min和*max是传递进去的参数,但是他们的作用是把值带出来。

指针应用场景二b:函数返回运算的状态,结果通过指针返回

  函数在运算的过程中遇到一些特殊的状态,或者说在函数运算时没有得到正确的结果,常用的套路是什么那?是让函数返回特殊的不属于有效范围内的值来表示出错。在C语言的标准库里,和文件操作相关的函数里能看到大量的这样的例子,这些函数要么返回-1要么返回0来表示这个操作没有成功。如果当函数返回任何值都是有效的可能结果时,0或者-1也是属于有效的,就没有办法通过返回值来表示结果是否正确,这时需要分开返回:函数的状态通过返回值来返回,实际的值通过指针参数来返回。这样做的好处是,可以容易的将结果放在if语句里去,看下两个值做除法的例子:

  1. #include <stdio.h>
  2. //return 如果除法成功,返回1;否则返回0
  3. int divide(int a,int b,int *result);
  4.  
  5. int main(void) {
  6. int a=;
  7. int b=;
  8. int c;
  9. if(divide(a,b,&c)){
  10. printf("%d/%d=%d\n",a,b,c);
  11. }
  12. return ;
  13. }
  14.  
  15. int divide(int a,int b,int *result){
  16. int ret=;
  17. if(b==) ret = ;
  18. else{
  19. *result=a/b;
  20. }
  21. return ret;
  22. }

  divide函数有三个参数,整数a和整数b,a除以b的结果放在第三个参数*result中,函数的返回值是如果除法是成功的,则返回值返回1,如果除数是0,让返回值为0,程序就终止不去做除法运算了产生异常返回0.在main里,如果返回值是1,条件满足打印输出abc的结果,如果返回值是0,条件不满足,不打印,因为如果除数b为0,c里是不能产生任何有意义的值。

  这种场景就是函数运算可能回出错,这种错误通过另外的场景表达出来,在c语言里只能这样。在后续的C++,java语言中,采用异常机制来解决这个问题。

指针最常见的错误:

  初学者在学习指针时最长犯的错误是,定义来指针变量,还没有指向任何变量,就开始使用指针。比如:

  1. int *p
  2. int k;
  3. k=;
  4. *p=;

  首先定义*p,*p没有指向任何一个变量,这个时候定义k,为k赋值。然后*p不是相当于一个变量吗,也为*p赋值一个值。这是不可行的,为什么?因为在定义时,*p是空的,没有指向任何一个具体的变量,没有被赋予一个实际的值,这个时候给*p赋值12,这个时候会发生的什么情况那,首先所有的本地变量都不会有默认的初始值,如果没有赋值就不会是个明确的值,可能是个乱七八糟的值,如果把这个乱七八糟的值当成一个地址的时候,p可能会指向一个莫名其妙的地方,所以当*p=12时,则就是把这个莫名其妙的地方写入12,但这个莫名其妙的地方恰巧是不可写的,这个时候程序就会崩溃。

  试一下,如果int *p=0,让*p指向一个明确的不应该去的地方,这个时候程序可能就会出现一个段错误(和编译器有关),也可能编译可以过去,但是运行时结果出现问题,另外如果*p不赋值,同样可能编译能够过去,但是总有一天会出错,你不能保证*p里不指向一个不可写或者不存在的地方。这两种情况,在devc++环境下,都是编译可过,运行时出现错误:

听翁恺老师mooc笔记(4)--指针的应用场景的更多相关文章

  1. 听翁恺老师mooc笔记(6)--指针运算

    指针值加1就是将指针值加上sizeof(指针所指变量的类型) 1+1=2,那么指针加1是加上了1这个数字吗?试一下,在代码中定义了char数组,char也是整数,数组名是ac,ac中有10个元素,0- ...

  2. 听翁恺老师mooc笔记(5)--指针与数组

    如果我们通过函数的参数将一个数组传递到参数中去,那么在函数里接收到的是什么东西呢?我们知道如果传递一个普通变量,那么参数接收到的是值,如果传递一个指针变量,参数接收到的也是值,只不过这时的值是地址.那 ...

  3. 听翁恺老师mooc笔记(3)--指针的定义

    在上一个blog学习了&运算符,使用&取了变量.数组等地址,有什么用那?如果能够将取得的变量的地址传递给函数,能否通过这个地址在函数内访问到外部这个变量?答案是肯定的,scanf(&q ...

  4. 听翁恺老师mooc笔记(16)--程序设计与C语言

    问题1:计算机遍布生活的各个方面,若你需要一个功能可以下载APP,我们需要的大部分功能都可以找到对应的APP,如果没有可以自己写一个软件,但是很少人需要这么做,那么我们为什么学习计算机编程语言? 学习 ...

  5. 听翁恺老师mooc笔记(12)--结构中的结构

    结构数组: 和C语言中的int,double一样,一旦我们做出一个结构类型,就可以定义这个结构类型的变量,也可以定义这个结构类型的数组.比如下面这个例子: struct date dates[100] ...

  6. 听翁恺老师mooc笔记(11)--结构和函数

    结构作为函数参数: 声明了一个结构就有了一种自定义的数据类型,这个数据类型和int.float.double一样,int等基本类型可以作为函数的参数,那么这种个自定义的结构类型也应该可以作为函数参数, ...

  7. 听翁恺老师mooc笔记(10)--结构

    定义结构: 在程序里,如果想要表达一个数据就需要一个变量,而每个变量又都需要一个类型,之前学过C语言中有int.double.float.char等这些基础类型,还有指针.数组等.如果你要表达的数据比 ...

  8. 听翁恺老师mooc笔记(8)--字符串2

    字符串的赋值 字符串的输入与输出 对C语言的基础类型,比如int.double等类型,scanf.printf有专门的格式转换,而对字符串,scanf.printf使用%s格式字符进行输入与输出.当使 ...

  9. 听翁恺老师mooc笔记(7)--字符串1

    C语言中字符串的定义 如果定义一个字符数组word,并使用大括号对其初始化,如下图所示: 但是这个不是C语言的字符串,只是字符数组,不是字符串,因为不能使用字符串的方式进行计算.那么C语言的字符串长什 ...

随机推荐

  1. LAMP应用部署

    LAMP+wordpress 部署博客 软件安装 yum -y install httpd yum -y install php yum -y install php-mysql yum -y ins ...

  2. Carries SCU - 4437

    Carries frog has nn integers a1,a2,-,ana1,a2,-,an, and she wants to add them pairwise. Unfortunately ...

  3. iBatis基础知识

    iBatis简介: 特点:结构性好,小巧,容易上手 搭建环境: 1.创建java 项目 2.导入(3个)jar包:ibatis-2.3.0.667.jar,mysql驱动包,Junit测试包 3.配置 ...

  4. [APIO2009]会议中心

    [APIO2009]会议中心 题目大意: 原网址与样例戳我! 给定n个区间,询问以下问题: 1.最多能够选择多少个不相交的区间? 2.在第一问的基础上,输出字典序最小的方案. 数据范围:\(n \le ...

  5. 【洛谷T7153】(考试) 中位数

    题目描述 给定 n 个数 a1, a2, ..., an,求这 n 个数两两的差值(共 n(n−1) 2 个)的中位数. 输入格式: 第一行一个正整数 n,表示数的个数. 接下来一行 n 个正整数,分 ...

  6. angular编写表单验证

    angular编写表单验证 一.整体概述 表单内容如下图,包括常用的用户名.密码.确认密码.手机.邮箱等 整体js代码很少,就一个指令用于写确认密码和密码是否相等.其他 验证都是使用angular自带 ...

  7. xx-net连接教程

    第一步:安装xx-net 在github上下载xx-net,网址 解压后点击运行start.bat文件,此时会提醒是不信任的文件,此时在系统偏好设置里的安全性与隐私去设置让它能打开. 第二步:安装Sw ...

  8. OSI模型和TCP/IP协议族(三)

    TCP/IP协议族 TCP/IP协议族的开发要比OSI模型更早,因此TCP/IP协议族的分层结构无法准确地与OSI模型一一对应.原始的TCP/IP协议族定义为建立再硬件基础上的四个软件层,不通过目前T ...

  9. PAT乙级-1036.跟奥巴马一起编程(15)

    题解 题解: 注意"行数是列数的50%(四舍五入)" #include<iostream> using namespace std; int main() { int ...

  10. C# 发送手机短信

    由于使用 收费 第三方 屏蔽   可能有 免费 第三方. private const string Cdkey = "8S*********************";密钥id p ...