我的c语言学习记录(蓝桥)————指针 上

指针

为了了解指针的概念,我们先来看一个小故事。

话说福尔摩斯派华生到威尔爵士居住的城堡去取回一个重要的数据。白天,在书房里,威尔爵士当着福尔摩斯和华生的面亲自将数据锁在了书柜中编号为 3010 的抽屉,用手电筒一照,只见里面有一张纸条,上面赫然写着 6 个大字:地址 2000。华生眼前一亮,迅速的找到了编号为 2000 的抽屉,取出了重要的数据 123,完成了任务。

可以用下图描述几个数据之间的关系。

 

说明

由此可见,指针变量是一种特殊的变量,它存放的不是数据,而是另一种变量的地址。这个存放数据的变量被称为指针变量所指向的目标变量。由于通过指针变量中的地址可以直接访问它指向的目标变量,常把指针变量简称为指针。

指针变量是一种存放地址的特殊变量,其特殊性表现在类型和值上。从变量角度讲,指针变量也具有变量的要素:

  • 指针变量的命名,与一般变量命名相同,遵循 C 语言的命名规则。
  • 指针变量的类型,是指针变量所指向的变量的类型,而不是自身的类型。
  • 在实验楼的环境中,指针变量在内存中占用 8 个字节。

先分析一个指针案例,通过指针变量访问整数类型。创建 10-1.c 文件并输入以下代码:

#include<stdio.h>

int main(){

 int a = 100,b = 10;

 int *point_1,*point_2;     //定义指向整型数据的指针变量 point_1,point_2

 point_1 = &a;                 //把变量 a 的地址赋给指针变量 point_1

 point_2 = &b;

 printf("a=%d,b=%d\n",a,b);

 printf("%p,%p\n",point_1,point_2);                     //输出 a 和 b 在内存中的地址

 printf("*point_1=%d,*point_2=%d\n",*point_1,*point_2);    //输出变量 a 和 b 的值

 return 0;

}

输入以下命令编译并运行:

gcc -o 10-1 10-1.c

./10-1

程序运行结果如下:

 

注意

如果指针打印出为负数,则需要将打印的类型 %d 调整为 %ld 才可以正常输出。调整成 %p 去匹配指针型最佳。

程序分析

  • 在开头处定义了两个指针变量 point_1  point_2。但此时他们并未指向任何一个变量,只是提供两个指针变量,规定他们可以指向整形变量,至于指向哪一个整形变量,要在程序语句中指定。

程序第 67 两行的作用就是使 point_1 指向 apoint_2 指向 b,此时 point_1 的值为 &a(即 a 的地址),point_2 的值为 &b

  • 10 行输出 *point_1  *point_2 的值,其中的 “*” 表示指向

其中 *point_1 表示指针变量 point_1 所指向的变量,也就是变量 a*point_2 表示指针变量 point_2 所指向的变量,也就是变量 b。从运行结果来看他们也就是 100 10

  • 程序中有两处出现 *point_1  *point_2,但是两者含义不同。

程序第 4 行的 *point_1  *point_2 表示定义两个指针变量 *point_1  *point_2。它们前面的 “*” 只是表示该变量是指针变量。程序最后 10 行中的 printf 函数中的 *point_1  *point_2 则表示指针变量 point_1  point_2 所指向的变量。

定义指针变量

10-1.c 中我们看到了定义指针变量,定义指针变量的一般形式为:

类型名 * 指针变量名

如:

int * point_1,* point_2;

上面定义的基类型为 int 的指针变量 point_1  point_2 只能用来指向整型的变量。

注意

我们在这里再次强调一遍,在定义指针变量时要注意,指针变量前面的 “*” 表示该变量的类型为指针型变量。指针变量名是 point_1  point_2,而不是 *point_1  *point_2。这是和定义整型或实型变量不同的。上面程序 6 行和 7 行是不能写成 * point_1=&a  *point_2=&b; 的。因为 a 的地址是赋给指针变量 point_1,而不是赋值给 *point_1(即变量 a)。

引用指针变量

在引用指针变量时,有以下 3 种情况:

1.给指针变量赋值。如:

p=&a;  //把 a 的地址赋给指针变量 p

引用指针变量指向的变量。

2.如果已经执行 p=&a; 即指针变量 p 指向了整型变量 a,则

printf("%d",*p);

其作用是以整数形式输出指针变量 p 所指向的变量的值,即变量 a 的值。

如果有以下赋值语句:

*p = 1;

表示将整数 1 赋给 p 当前所指向的变量,如果 p 指向变量 a,则相当于把 1 赋给 a,即 a=1;

引用指针变量的值。如:

printf("%o",p);

作用是以八进制数形式输出指针变量 p 的值,如果 p 指向了 a,就是输出了 a 的地址,即 &a

注意

比较地址运算符 & 和指针运算符 * 的差异:

 

输入两个整数,按先大后小的顺序输出 a b

解题思路

用指针的方法来处理这个问题。不交换整形变量的值,而是交换两个指针变量的值。

编写源程序 10-2.c

#include<stdio.h>

int main(){

    int *p1,*p2,*p,a,b;

    printf("please enter two integer number:");

    scanf("%d,%d",&a,&b);

    p1 = &a;

    p2 = &b;

// 注意:这里是交换指针的值

// 即指针的指向发生了改变

// 但是两个变量 a b 的值是没有改变的

    if(a<b){

        p = p1;

        p1 = p2;

        p2 = p;          //使 p1 p2 的值互换

    }

// 如果 a < b,通过结果可以观测到 p1 指向 bp2 指向 a

    printf("a=%d,b=%d\n",a,b);

    printf("max=%d,min=%d\n",*p1,*p2);

    return 0;

}

程序运行结果如下:

 

程序分析

输入 23 42,由于 a<b,将 p1 p2 交换,交换前后的情况如下图:

 

注意

  • a 和 b 的值并未交换,他们仍然保持原值,但 p1 和 p2 的值改变了。p1 的值原来为 &a,后来变为 &b。这样输出 *p1 和 *p2 时,实际上输出变量 b 和 a 的值,所以先输出 42,然后输出 23。
  • 程序中 p=p1;p1=p2;p2=p; 这个语句是我们之前使用过的方法,两个变量的值交换要利用第三个变量。实际上学到指针我们可以用更加简洁的方法把 p=p1;p1=p2;p2=p; 改为 p1=&b,p2=&a,这样就不需要定义中间变量 p,使得程序更加简洁。

指针变量作为函数参数

函数的参数不仅可以是整形,浮点型等数据,也可以是指针类型。他的作用是将一个变量的地址传送到另一个函数中。

下面通过一个例子来说明:要求实现的功能和 10-2.c 相同,只不过这次我们采用函数来处理,而且用指针类型的数据做函数的参数。

编写源程序 10-3.c

#include<stdio.h>

int main(){

    void swap(int * point_1,int * point_2);

    int *p1,*p2,a,b;

    printf("please enter two integer number:");

    scanf("%d,%d",&a,&b);

    p1 = &a;

    p2 = &b;

    if(a<b)

        swap(p1,p2);

// 如果 a < b,那么 a b 的值进行了交换

// 如果打印了 *p1 *p2 我们会发现,p1 仍指向 ap2 仍指向 b

    printf("max=%d,min=%d\n",a,b);

    return 0;

}

void swap(int * point_1,int * point_2){

    int temp;

// 注意:这里是交换指针所指变量的值

// 即指针的指向没有发生改变

// 但是变量 a b 的值改变了

    temp = * point_1;                 //使 *p1 *p2 互换

    *point_1 = * point_2;

    *point_2 = temp;

}

程序运行结果如下:

 

程序分析:

swap 是用户自定义函数,它的作用是交换两个变量(a b)的值。

swap 函数的两个形参 point_1 point_2 是指针变量。程序运行时,先执行 main 函数,输入 a b 的值(我们输入的是 23 34),然后将 a b 的地址分别赋给 int 指针变量 p1 p2,使 p1 指向 ap2 指向 b,见下图 a,接着执行 if 语句,由于 a<b,因此执行 swap 函数。

注意实参 p1 p2 是指针变量,在函数调用时,将实参变量的值传送给形参变量,采取的依然是值传递方式。因此虚实结合后形参 point_1 的值是 &apoint_2 的值为 &b,见下图 b。这时 p1 point_1 都指向变量 ap2 point_2 都指向变量 b 接着执行 swap 函数的函数体,使 * point_1 * point_2 的值互换,也就是使 a b 的值互换。互换后的情况见图 c

函数调用结束后,形参 point_1 point_2 不复存在(已释放),情况如图 d,最后在 main 函数中输出的 a b 的值已经是经过交换的值。

 

可以看到,在执行 swap 函数后,变量 a b 的值改变了。

注意:请仔细分析,这个改变是怎么实现的,这个改变不是通形参值传回实参实现的。大家可以考虑下能否通过下面的函数实现 a b 互换。

void swap(int x ,int y){

    int temp;

    temp = x;

    x = y;

    y = temp;

}

如果在 main 函数中调用 swap 函数:swap(a,b); 会有什么结果?

在函数调用时,a 的值传送给 xb 的值传送给 y,执行完 swap 函数后,x y 的值是互换了,但并未影响到 a b 的值。

在函数结束时,变量 x y 释放了,main 函数中的 a b 并未互换。也就是说,这种单向的值传递,形参值的改变不能使实参的值随之改变。

为了使在函数中改变了的变量值能被主调函数 main 所用,不能采取上述的把要改变的变量作为参数的办法,而应该用指针变量作为函数参数,在函数执行过程中使指针变量所指向的变量值发生变化,函数调用结束后,这些变量值依然保留了下来。

如果想通过函数调用得到 n 个要改变的值,可以这样做:

  1. 在主调函数中设 n 个变量,用 n 个指针变量指向它们;
  2. 设计一个函数,有 n 个指针形参,在这个函数中改变 n 个形参的值;
  3. 在主调函数中调用这个函数,在调用时将这 n 个指针变量作实参,将他们的地址传给该函数的形参;
  4. 在执行该函数的过程中,通过形参指针变量,改变它们所指向的 n 个变量的值;
  5. 主调函数中就可以使用这些改变了值的变量了。

大家是不是转的有点晕,你把刚才的程序再写两遍,下面的这个程序练习再来好好写一遍并独立思考你绝对掌握了。输入 3 个整数 abc 要求按从大到小的顺序将他们输出,用函数实现。

解题思路:

采用 10-3.c 的方法在函数中改变 3 个变量的值。用 swap 函数交换两个变量的值,用 exchange 函数改变着 3 个变量的值。

编写源程序 10-4.c

#include<stdio.h>

int main(){

    void exchange(int * q1,int * q2,int * q3);

    int a,b,c,*p1,*p2,*p3;

    printf("please enter 3 integer number:");

    scanf("%d%d%d",&a,&b,&c);

    p1 = &a;

    p2 = &b;

    p3 = &c;

    exchange(p1,p2,p3);

    printf("the order is :%d,%d,%d\n",a,b,c);

    return 0;

}

void exchange(int *q1,int *q2,int *q3){

    void swap(int *p1,int *p2);

    if(* q1<* q2) swap(q1,q2);

    if(* q1<* q3) swap(q1,q3);

    if(* q2<* q3) swap(q2,q3);

}

void swap(int *p1,int *p2){

    int temp;

    temp = *p1;

    *p1 = *p2;

    *p2 = temp;

}

程序运行结果如下:

 

请小伙伴自己画出类似于我们上一个例题那样的图来,仔细分析变量的值变化的过程,不要偷懒!

通过指针引用数组

可以用一个指针变量指向一个数组元素。例如:

int a[10]={1,2,3,4,5,6,7,8,9,10};

int *P;

p = &a[0];

以上是使指针变量 p 指向 a 数组的第 0 号元素。

C 语言中,数组名(不包括形参数组名,形参数组并不占据实际的内存单元)代表数组中首元素(即序号为 0 的元素)的地址。因此,下面两个语句等价:

p = &a[0];  //p 的值是 a[0] 的地址

p = a;      //p 的值是数组 a 首元素(即 a[0])的地址

注意:

数组名不代表整个数组,只代表数组首元素的地址。上述 p=a; 的作用是 a 数组的首元素的地址赋给指针变量 p”,而不是把数组 a 各元素的值赋给 p”

通过指针对数组元素进行操作

程序举例

在指针指向数组元素时,可以对指针进行以下运算:

  • 加减一个整数,如 p+1; 或者 p-1;
  • 自加运算,如 p++ 或者 ++p
  • 自减运算,如 p--或者 --p

分别说明如下:

  1. 如果指针变量 p 已指向数组中的一个元素,则 p+1 指向同一数组中的下一个元素,p-1 指向同一数组中的上一个元素。注意:执行 p+1 时并不是将 p 的值(地址)简单地加 1,而是加上一个数组元素所占用的字节数。例如,数组元素是 float 型,每个元素占 4 个字节,则 p+1 意味着使 p 的值加 4 个字节,以使它指向下一个元素。p+1 所代表的地址实际上是 p+1*d,d 是一个数组元素所占的字节数。若 p 的值是 2000,则 p+1 的值不是 2001 而是 2004。
  2. 如果 p 的初值为 &a[0],则 p+i 和 a+i 就是数组元素 a[i] 的地址,或者说,他们指向 a 数组序号为 i 的元素,见下图,这里注意的是 a 代表数组首元素的地址,a+1 也是地址,它的计算方法同 p+1,即它的实际地址为 a+1*d。例如,p+9 和 a+9 的值是 &a[9],它指向 a[9]。

     3.*(p+i)和 *(a+i) 是 p+i 或 a+i 所指向的元素,即 a[i]。例如 *(p+5) 和 *(a+5) 就是 a[5],三者等价。

 

有一个整型数组 a,有 10 个元素,要求输出数组中的全部元素。

编写源程序 10-5.c

#include<stdio.h>

int main(){

    int a[10];

    int i;

    printf("please enter 10 integer numbers: ");

    for(i=0;i<10;i++)

        scanf("%d",&a[i]);

    for(i=0;i<10;i++)

        printf("%d\t",a[i]);     //数组元素用数组名和下标表示

    return 0;

}

编写源程序 10-6.c

#include<stdio.h>

int main(){

    int a[10];

    int i;

    printf("please enter 10 integer numbers: ");

    for(i=0;i<10;i++)

        scanf("%d",&a[i]);

    for(i=0;i<10;i++)

        printf("%d\t",*(a+i));  //通过数组名和元素序号计算元素地址,再找该元素

    return 0;

}

编写源程序 10-7.c

#include<stdio.h>

int main(){

    int a[10];

    int *p,i;

    printf("please enter 10 integer numbers: ");

    for(i=0;i<10;i++)

        scanf("%d",&a[i]);

    for(p=a;p<(a+10);p++)

        printf("%d\t",*p);  //用指针指向当前的数组元素

    return 0;

}

运行三个程序,程序运行结果如下:

 

可以看出,结果是一样的。

由于窗口大小限制,最上方的命令 ./10-5 没有显示在图片中。

程序分析

  • 10-6.c 程序中的 scanf("%d",&a[i]); 可以修改为 scanf("%d",a+i);。也可以改用 a+i 表示 a[i] 的地址。
  • 10-7.c 程序中的 scanf("%d",&a[i]); 可以修改为 scanf("%d",a+i);。用指针变量表示当前的地址。

下面让我们动手试试看!

3 种方法的比较:

  • 第 1 种和第 2 种方法的执行效率是相同的。C 编译系统是将 a[i] 装换为 *(a+i) 处理的,即先计算元素的地址。因此用第 1 和第 2 种方法找数组元素费时较多。
  • 第 3 种方法比第 1、第 2 种方法快,用指针变量直接指向元素,不必每次都重新计算地址,像 p++ 这样的自加操作是比较快的。这种有规律的改变地址值 p++ 能大大提高执行效率。
  • 用下标比较直观,能直接知道是第几个元素。例如,a[5] 是数组中序号为 5 的元素(注意序号是从 0 算起)。用地址发或者指针变量的方法不直观,难以很快的判断出当前处理的是哪一个元素。例如,方法 3 中,要仔细分析指针变量 p 的当前指向,才能判断当前输出的是第几个元素。有经验的程序猿往往喜欢用第 3 种形式,用 p++ 进行控制,程序简洁、高效。对于小白用户最好还是用第 1 种方式,直观,不易出错。

在使用指针变量指向数组元素时,有一些问题需要注意:

可以通过改变指针变量的值指向不同的元素。例如:上述第 3 种方法是用指针变量 p 来指向元素,用 p++ 使 p 的值不断改变从而指向不同的元素。

如果不用 p 变化的方法而用数组名 a 变化的方法行不行呢?假如将上述第 3 中方法中的程序的

for(p=a;p<(a+10);p++)

printf("%d\t",*p);

改为:

for(p=a;a<(p+10);a++)

printf("%d",*a);

这样是不行的。因为数组名 a 代表数组首元素的地址,它是一个指针型常量,它的值在程序运行期间是固定不变的。既然 a 是常量,所以 a++ 是无法实现的。值得注意的它的值虽然不能改变,但是在程序中我们可以使用 a+i 表示 a[i],这里 a+i  a++ 不同在于它并没有修改常量 a 的值(单独使用时,a++ 是等价于 a=a+1,它对 a 的值进行了修改)。

指针变量指向数组元素注意指针变量的当前值。

编写源程序 10-8.c

#include<stdio.h>

int main(){

    int i,*p,a[10];

    p=a;

    printf("please enter 10 integer number:");

    for(i=0;i<10;i++)

        scanf("%d",p++);

    for(i=0;i<10;i++,p++)

        printf("%d\t",*p);

    printf("\n");

    return 0;

}

程序运行结果如下:

 

程序分析

显然输出的数值并不是 a 数组中各元素的值。需要检查和分析程序。

可能大家会觉得上面的程序没有什么问题,即使已被告知此程序有问题,还是找不出问题出在哪里。问题出在指针变量 p 的指向。指针变量 p 的初始值为 a 数组首元素的地址,但经过第一个 for 循环读入数据后,p 已指向 a 数组的末尾。因此,在执行第 2 for 循环时,p 的起始值不是 &a[0] 了,而是 a+10。由于执行第 2 for 循环时,每次要执行 p++,因此 p 指向的是 a 数组下面的 10 个存储单元。

解决这个问题的方法只需要在第 2 for 循环之前加一个赋值语句:

p = a;

使 p 的初始值重新等于 &a[0],这样的结果就对了。

归纳分析

根据以上叙述,引用一个数组元素,可以用下面两种方法:

  1. 下标法,如 a[i],p[i] 的形式;直观,不易出错。
  2. 指针法,如 *(a+1) 或 *(p+i)。其中 a 是数组名,p 是指向数组元素的指针变量,其初值 p=a。

遍历数组的成员可用:

  1. 下标法,如 a[2];
  2. 通过数组名计算数组元素地址,找出元素的值;
  3. 用指针变量指向数组元素。

注意:

p[i]*(p+i) 的形式必须先使 p = a

利用指针引用数组元素,比较方便灵活,有不少技巧。在专业人员中常喜欢用一些技巧,以使程序简洁。我们来分析下面几种情况。

  1. p++ 使 p 指向下一个元素 a[1]。然后若在执行 * p,则得到下一个元素 a[1] 的值。

p++;

* p;

  1. 由于 ++ 和 * 同优先级,结合方向为自右而左,因此它等价于 *(p++)。先引用 p 的值,实现 *p 的运算,然后再使 p 自增 1。

*p++;

  1. *(p++) 与 *(++p) 作用是否相同?答案肯定是不相同的。前者是先取 *p 的值,然后使 p 加 1。后者是先使 p 加 1,再取 *p。

用数组名做函数参数

程序举例

在数组章节我们介绍过可以用数组名作为函数的参数。例如:

int main(){

    void fun(int arr[],int n);

    int array[10];

             .

             .

             .

    fun(array,10);      //用数组名作为函数的参数

    return 0;

}

void fun(int arr[],int n){

        .

        .

        .

}

array 是实参数组名,arr 为形参数组名。从前两节我们应该知道,当用数组名作为参数时,如果形参数组中各元素的值发生变化,实参数组元素的值随之变化。这究竟是何原因呢?学过我们上一节指针的话应该不难理解。

程序分析:

  • 先看数组元素为实参时的情况。如果已经定义一个函数,其原型为void swap(int x,int y);,假设函数的作用是将两个形参 (x,y) 的值交换,现有以下的函数调用swap(a[1],a[2]);。用数组元素 a[1] 和 a[2] 作为实参的情况,与用变量作实参时一样,是“值传递”的方式,将 a[1] 和 a[2] 的值单向传递给 x 和 y。当 x 和 y 的值改变时 a[1] 和 a[2] 的值并没有改变。
  • 我们再来看数组名作为函数参数的情况,实参数组名代表该数组首元素的地址,而形参是用来接收从实参传递过来的数组首元素地址的。因此,形参应该是一个指针变量。实际上 C 编译系统是将形参数组名作为指针变量来处理的。
    • 例如 fun(int arr[],int n) ,在程序编译时是将 arr 按指针变量处理的,相当于将函数 fun 的首部写成 fun(int *arr,int n);。 上面的两种写法是等价的。在该函数被调用时,系统会在 fun 函数中建一个指针变量 arr,用来存放从主调函数传递过来的实参数组首元素的地址。当 arr 接收了实参数组的首元素地址后,arr 就指向实参数组首元素,也就是指向 array[0]。因此 *arr 就是 array[0],*(arr+1) 就是 array[1]。
    • 我们可以这样来理解,在函数调用期间,形参数组从实参数组那里得到起始地址,因此形参数组与实参数组共占同一段内存单元,在调用函数期间,如果改变了形参数组的值,也就是改变了实参数组的值。

C 语言常用这种方法通过调用一个函数来改变实参数组的值。将数组 a n 个整数按相反的顺序存放,见下图:

 

解题思路

a[0] a[n-1] 对换,再将 a[1] a[n-2] 对换...直到将 a[int (n-1)/2] a[n-int(n-1)/2-1] 对换。现用循环处理此问题,设两个位置指示变量” i ji 的初的 0j 的初值为 n-1。将 a[i] a[j] 交换,然后是 i 的值加 1j 的值减 1,再将 a[i] a[j] 交换,直到 i=(n-1)/2 为止。

用一个函数 change 来实现交换。实参用数组名 a,形参可用数组名,也可用指针变量名。

编写源程序 10-9.c

#include<stdio.h>

int main(){

    void change(int x[],int 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\t",a[i]);

    printf("\n");

    change(a,10);

    printf("the array has been inverted:\n");

    for(i=0;i<10;i++)

        printf("%d\t",a[i]);

    return 0;

}

void change(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;

    }

}

编写源程序 10-10.c

#include<stdio.h>

int main(){

    void change(int *x,int 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\t",a[i]);

    printf("\n");

    change(a,10);

    printf("the array has been inverted:\n");

    for(i=0;i<10;i++)

        printf("%d\t",a[i]);

   return 0;

}

void change(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;

    }

}

运行两个程序,程序运行结果如下:

 

结果是一致的,也就是说都实现了交换的功能。

程序分析

实际上 10-9.c 这个程序我们可以做一些改动就可以得到程序 10-10.c

将函数 change 中的形参 x 改成指针变量。相应的实参仍为数组名 a(即数组 a 首元素的地址),将它传给形参指针变量 x,这时 x 就指向 a[0]x+m a[m] 元素的地址。设 j i 以及 p 都是指针变量,用它们指向有关元素。i 的初值 xj 的初值为 x+n-1,见下图。使得 *i *j 交换就是 a[i] a[j] 交换。

 

归纳分析

如果有一个实参数组,要想在函数中改变数组中的元素的值,实参和形参的对应关系有以下 4 种情况。

形参和实参都用数组名,例如:

int main(){

  int a[10];

  .

  .

  .

  f(a,10);

}

int f(int x[],int n){

  .

  .

  .

}

由于形参数组名 x 接收了实参数组首元素 a[0] 的地址,因此可以认为在函数调用期间,形参数组与实参数组共用一段内存单元,这种形式比较好理解。

实参用数组名,形参用指针变量。例如:

int main(){

  int a[10];

  .

  .

  .

  f(a,10);

}

void f(int *x,int n){

  .

  .

  .

}

实参 a 为数组名,形参 x 为 int * 型的指针变量,调用函数开始后,形参 x 指向 a[0],即 x=&a[0],通过 x 的值的改变,可以指向 a 数组的任一元素。例 11-2.c 就属于此类。

实参形参都用指针变量。例如:

int main(){

    int a[10],*p=a;

    .

    .

    .

    f(p,10);

    .

    .

    .

}

void f(int *x,int n){

  .

  .

  .

}

实参 p 和形参 x 都是 int * 型的指针变量。先使实参指针变量 p 指向数组 a[0],p 的值是 &a[0]。然后将 p 的值传给形参指针变量 x,x 的初始值也是 &a[0],通过 x 的值的改变可以使 x 指向数组 a 的任意元素。

实参为指针变量,形参为数组名。例如:

int main(){

    int a[10],*p=a;

    .

    .

    .

    f(p,10);

}

void f(int x[],int n){

  .

  .

  .

  .

}

实参 p 为指针变量,它指向 a[0]。形参为数组名 x,编译系统把 x 作为指针变量处理,今将 a[0] 的地址传给形参 x,使 x 也指向 a[0]。也可以理解为形参数组 x a 数组共用同一段内存单元。在执行过程中可以使 x[i] 的值变化,而 x[i] 就是 a[i]。这样,main 函数可以使用变化了的数组元素的值。

以上 4 种方法,实质上都是地址的传递。其中 3 4 两种只是形式上不同,实际上形参都是使用指针变量。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值