指针变量作为函数参数
- 函数的参数不仅可以是整型、浮点型、字符型等数据,还可以是指针类型。
- 它的作用是将一个变量的地址传送到另一个函数中。
- 例如:
void swap(int *a,int *b)
#include <stdio.h>
void main() {
void swap(int *x, int *y);
int a,b;
int *a1 = &a;
int *b1 = &b;
printf("请输入a,b的值:\n");
scanf_s("%d %d", &a, &b);
if (a < b) {
swap(a1, b1);
}
printf("max = %d, min=%d\n", a, b);
}
void swap(int *x, int *y) {
int p;
p = *x;
*x = *y;
*y = p;
}
- 注意:
函数的调用可以(而且只可以)得到一个返回值(即函数值),而使用指针变量作参数,可以得到多个变化了的值。如果不用指针变量是难以做到这一点的。 如果想通过函数调用得到n个要改变的值
- 1.在主调函数中设n个变量,用n个指针变量指向它们;
- 2.设计一个函数,有n个指针形参。在这个函数中改变这n个形参的值;
- 3.在主调函数中调用这个函数,在调用时将这n个指针变量作实参,将它们的地址传给该函数的形参;
- 4.在执行该函数的过程中,通过形参指针变量,改变它们所指向的n个变量的值;
- 5.主调函数中就可以使用这些改变了值的变量。
- 例子
输入3个整数a,b,c,要求按由大到小的顺序将它们输出。用函数实现。
#include <stdio.h>
void main() {
void exchange(int *x, int *y,int *z);
int a,b,c;
int *a1 = &a;
int *b1 = &b;
int *c1 = &c;
printf("请输入a,b,c的值:\n");
scanf_s("%d %d %d", &a, &b, &c);
exchange(a1,b1,c1);
printf("%d, %d, %d\n", a,b,c);
}
void swap(int *x, int *y) {
int p;
p = *x;
*x = *y;
*y = p;
}
void exchange(int *x, int *y, int *z) {
void swap(int *x, int *y);
if (*x < *y) {
swap(x, y);
}
if (*x < *z) {
swap(x, z);
}
if (*y < *z) {
swap(y, z);
}
}
数组元素的指针
- 一个变量有地址,一个数组包含若干元素,每个数组元素都有相应的地址。
- 指针变量可以指向数组元素(把某元素的地址放到一个指针变量中)。
- 数组元素的指针就是数组元素的地址。
引用数组元素时指针的运算
在指针指向数组元素时,允许以下运算:
- 一加一个整数(用 + 或 +=),例如:
p + 1
- 一减一个整数(用 - 或 -=),例如:
p - 1
- 一两个指针相减,如 p1-p2 (只有p1和p2都指向同一数组中的元素时才有意义)
- 一加一个整数(用 + 或 +=),例如:
如果指针变量p已指向数组中的一个元素
- p+1指向同一数组中的下一个元素;
- p-1指向同一数组中的上一个元素。
如果p的初值为&a[0],则
- p+i 和 a+i 就是数组元素a[i]的地址,
- 或者说,它们指向a数组序号为i的元素。
- 例如
#include <stdio.h>
void main() {
int a[5] = {1,2,3,4,5};
int *a1 = &a[0]; // 或者 int *a1 = a
printf("%d, %d\n", *a1, a1);
a1 = a1 + 2;
printf("%d, %d\n",*a1, a1);
}
当p指向a数组首元素时,数组元素 a[i] 的地址表达式有以下四种:
&a[i]
a + i
p + i
&p[i]
当p指向a数组首元素时,数组元素 a[i] 的值表达式有以下四种:
a[i]
*(a + i)
*(p + i)
p[i]
a 和 p 是有本质的区别:
- a 是指针常量,其值不可变;
- p 是指针变量,其值可变。
- 所以,a++、a = p 等都是非法表达式;
- 而 p++、p = a都是合法的表达式。
如果 指针p1 和 p2 都指向同一数组
- p2 - p1 用来计算 p2所指的元素 与 p1所指的元素 之间有多少个元素。
- 两个指针变量相减 的含义是 两个地址之差 除以 每个数组元素所占的字节数。
- 例子
#include <stdio.h>
void main() {
int a[10] = {1,2,3,4,5,6,7,8,9,10};
int *p1 = &a[0];
int *p2 = &a[6];
printf("p1的地址:%d\n",p1);
printf("p2的地址:%d\n",p2);
printf("%d\n", p2 - p1);
printf("%d\n",*p2 - *p1); // int 为4个字节
}
*++p
,等价于*(++p)
,先使p+1
即指向下一个数组元素,再取*p
作为此表达式的值。*p++
,等价于*(p++)
,取p
作为此 表达式的值,再使p+1
。(*p)++
,先取p
所指向的 元素值 作为 此表达式的值,再将 该元素值加1。++(*p)
,将p
所指向的 元素值加1 作为 此表达式的值。
#include <stdio.h>
void main() {
int a[10] = {1,2,3,4,5,6,7,8,9,10};
int *p = &a[0];
printf("%d\n",*p);
printf("%d\n",*++p);
printf("%d\n",*p++);
printf("%d\n",(*p)++);
printf("%d\n",++(*p));
}
通过指针引用数组元素
引用一个数组元素,可用下面两种方法:
- 1.下标法,例如:
a[i]
- 2.指针法,例如:
*(a+i)
或*(p+i)
其中a是数组名,p 是指向数组元素的指针变量,其初值 p = a
- 1.下标法,例如:
- 例子
有一个整型数组a,有10个元素,要求输出数组中的全部元素。
#include <stdio.h>
void main() {
int a[10] = {1,2,3,4,5,6,7,8,9,10};
int *p;
// 下标法
for (int i = 0; i < 10; i++) {
printf("%d ", a[i]);
}
printf("\n");
// 通过数组名计算数组元素地址
for (int i = 0; i < 10; i++) {
printf("%d ", *(a+i));
}
printf("\n");
// 指针法
for (p=a; p <a+10; p++) {
printf("%d ", *p);
}
printf("\n");
}
3种方法的比较:
- 第(1)和第(2)种方法执行效率相同
- C编译系统是将
a[i]
转换为*(a+i)
处理的,即先计算元素地址。 因此用第(1)和第(2)种方法找数组元素费时较多。
- 第(3)种方法比第(1)、第(2)种方法快
- 用指针变量直接指向元素,不必每次都重新计算地址。
这种有规律地改变地址值 例如
p++
能大大提高执行效率。- 用下标法比较直观,能直接知道是第几个元素。
- 用地址法或指针变量的方法不直观,难以很快地判断出当前处理的是哪一个元素。
评论