• 第三次课大纲


      在第二次课学习了指针的定义和引用,那么指针有什么用那?主要是两个用途,一种是将指针作为子函数参数时,在子函数内部可以对外面的变量进行修改;二是函数只有一个返回值,当需要返回多个值的时候可以通过将指针作为函数参数来完成。

    (1)指针作为函数参数

      在学习函数调用时,函数参数的传递是值传递,即将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。比如下面的例子,如果再g函数中修改k的值i的值是否会改变?大家可以试验下:

     1 #include <stdio.h>
     2 void g(int k);
     3 
     4 int main(void) {
     5     int i=6;
     6     printf(" i=%d
    ",i);
     7     g(i);
     8     return 0;
     9 }
    10 
    11 void g(int k){
    12     printf(" k=%d
    ",k);
    13 }
    View Code

      结果肯定i的值不会改变。那么如果将参数换成指针那?参照g函数再写一个f函数(对照着g解释f): 

     1 #include <stdio.h>
     2 void g(int k);
     3 void f(int *p);
     4 
     5 int main(void) {
     6     int i=6;
     7     g(i);
     8     printf(" &i=%p
    ",&i);
     9     f(&i);
    10     return 0;
    11 }
    12 
    13 void f(int *p){
    14     printf(" p=%p
    ",p);
    15 } 
    16 
    17 void g(int k){
    18     printf(" k=%d
    ",k);
    19 }
    View Code

      从这个例子看出g和f函数很类似,只是传递的参数的类型不同,一个是整数类型,一个是指针类型,都是值传递,g传递的是整数,f传递的是一个地址。

      我们知道在g函数里修改的k的值,i的值没有变化,那么如果在f里修改*p的值,main里i的值是否变化那?再上述程序上添加代码如下:

     1 #include <stdio.h>
     2 void f(int *p);
     3 void g(int k);
     4 
     5 int main(void) {
     6     int i=6;
     7     printf("&i=%p
    ",&i);
     8     f(&i);
     9     g(i);
    10     printf("i=%d
    ",i);
    11     return 0;
    12 }
    13 
    14 void f(int *p){
    15     printf(" p=%p
    ",p);
    16     printf("*p=%d
    ",*p);
    17     *p = 26;
    18 }
    19 
    20 void g(int k){
    21     printf(" k=%d
    ",k);
    22 }
    View Code

      在调用f函数之后调用g函数和输出i的值,发现i的值和k的值都发生了变化。这就是g和f函数的不同点:c语言的函数在调用时发生的参数的转移是一种值的传递,我们把值传进了函数,所以函数和调用它的地方没用任何的联系,现在情况有点不一样了,但是我们仍然坚持说,现在这个传递依然是值的传递,地址值被传进了函数,但是因为传进来的是地址,所以通过这个地址在函数内部可以以*p的方式访问到外面的变量的值。

    (2)函数通过指针返回多个值

      那么在子函数里可以访问到main中的变量又有什么用那?再看swap例子(听课笔记:指针的应用场景),当传递到swap中的是整型数值时,交换只发生在swap函数内部。而当传递的是指针类型的地址时main里的两个值也实现了交换。为什么?如下图所示。

      所以以指针作为函数参数时,可以在函数内部访问到外面变量,如何访问,可以读可以写。

      在上面的例子中,swap函数在做交换后,返回来2个值,只返回a不够,还应该返回b。这种让子函数返回两个值的需求,通过函数的返回值是不能实现的,但是通过指针就可以实现,如何实现?通过指针带回,也就是说传入的参数实际上是需要保存带回的结果的变量。再看下例,(2.1)函数返回运算的状态,结果通过指针返回(以听课笔记:指针的应用场景中的divide为例进行说明)

      以上2点就是指针的主要用途,那么这两点在使用指针操作数组时也很常见,并且利用指针可以替代通过数组下标所能完成的所有操作,并且利用指针编写的程序比数组下标编写的程序执行速度还要快,下面讨论下指针和数组的关系:

    (1)数组中各元素的地址

      使用int a[10]定义数组a,其实是在内存里申请了10个存储空间,每个单元都有相应的地址,那我们输出各个单元地址查看他们的地址有什么关系:

      从结果可以看出:通过a[0]、a[1]、a[2]的地址可以发现数组各元素的地址是递增的关系,并且每个元素地址之间的差值是4(可以尝试将所有数组元素的地址都输出出来验证),注意和相邻变量的地址分配是不一样的,相邻变量中后定义的变量比先定义的地址要小。

    (2)数组名是一个特殊的指针

      另外从上述实验结果可以看出:&a=a=&a[0],在c语言中,数组的地址就是数组首元素a[0]的地址,数组名a本身就是地址,就是这个首地址,可以不使用&取地址符,所以要求数组地址时直接输出数组名就可以。在前面介绍过,指针变量的值就是地址,那么数组名a的值也是地址,可否当指针使用?能否对a使用*运算符,下面试一下:

      从结果可以看出完全可以,对a进行*运算和[]运算结果是一样的,都是取该地址指向的变量的值。

      既然a可以使用*运算符,那么将a赋值给指针变量p,变量p是否也可当数组首地址,对p进行[]运算符那?,比如输出数组中第5个元素的值,其实直接打印a[4]即可实现,那么p[4]结果是什么那?

      从结果看出p也可以做[]运算来访问数组中的每个元素,那么是不是就说明指针p和数组名a就是一样的?或者数组名a就是一个普通指针那?答案是否定的,实际上数组名a是const常量指针,在之前讲数组时说到过,如果定义两个数组,int a[],int b[],使a=b是不可以的,数组之间是不能赋值的。而int *q=a,这个是可以的,一个不可以一个可以有什么区别那?实际上我们说的int a[]可以被看作int * const a,const意思是a是常量,不可以改变,它是这个数组就不可以是别的数组了,所以数组名在被当作值使用时,可理解为或者相当于一个常量指针,不可以赋值,不可以代表别的东西

     (3)数组名作为函数参数

      我们知道如果通过函数参数传递一个普通变量,那么参数接收到的是值,如果传递一个指针变量,参数接收到的也是值,只不过这时的值是地址。那么数组是什么?将数组作为值传给一个函数,在函数的参数里有一个数组变量来接收这个数组,看下到底接收到数组变量的什么东西呢?

      新建test函数,以数组作为参数,输出a在main和test中的值,结果地址是一样的,这说明什么,说明在test里的这个数组就是main里的这个数组,他们是同一个。再比如在test中修改a[2]的值,然后在main中调用完test函数后输出a[2]的值,发现确实结果确实改变了。

      那么在test函数中能不能计算出数组a的个数?在test和main中分别添加printf函数:

      从结果可以看出,在main里a的大小是64,而在test函数中数组a的大小为8,8是什么,在64位机器下,8刚好和一个指针的大小是一样的,和地址的大小是一样的。test参数中int a[]就是指针,那么将这个参数修改为int a[10],在test中sizeof没有办法得到这个数组元素的个数,原因就在于它其实就是个指针,它只是样子看上去像一个数组,那么既然它实际上是一个指针,我们把它写成像一个指针行不行,a[]写成*a,发现编辑和运行结果都没有变化。所以我们可以说数组和指针存在某种联系:函数参数中的数组实际上是指针,也就是说sizeof(a)= siziof(int*),但是对于这种指针可以使用数组的方括号[]运算符来进行运算。

    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    学生反应知识点有点多,前后关联性不强,指针作为函数参数应该和第二次课讲,而数组和指针是一次课。

  • 相关阅读:
    (最小路径覆盖) poj 1422
    (匈牙利算法) hdu 2119
    (匈牙利算法) hdu 4185
    (匈牙利算法) hdu 2063
    (匈牙利算法)hdu 1281
    (匈牙利算法DFS)hdu 3729
    (01 染色判奇环) hdu 3478
    (多重背包)poj 1276
    (判断欧拉回路)poj 1368
    (差分约束) hdu 1384
  • 原文地址:https://www.cnblogs.com/c-programing-language/p/6505149.html
Copyright © 2020-2023  润新知