指针
- 指针
- 直接访问与间接访问
- 指针变量
- 指针变量作为函数参数
- 通过指针引用数组
- 指向函数的指针
- 返回指针值的函数
- 指针数组
- 例题汇总
-
- 例8.1初识指针
- 例8.2引用指针变量(排序)
- 例8.3指针变量函数
- 例8.4指针变量函数的错误示范
- 例8.5
- 例8.6通过指针引用数组元素(输出数组元素)
- 例8.7通过指针输出数组元素(最快读取)
- 例8.8通过指针引用数组(反顺序)
- 例8.9用指针变量作参数
- 例8.10形参采用指针变量(便于理解,推荐使用)
- 例8.16输出字符串
- 例8.17采用指针实现字符串输出
- 例8.18复制字符串
- 例8.19复制字符串(使用指针变量)
- 例8.20字符指针作函数参数(复制字符串)
- 例8.21改变指针变量的值
- 例8.22通过指针调用函数
- 例8.23通过指针调用函数
- 例8.24指向函数的指针
- 例8.25返回指针的函数
- 例8.26
- 例8.27指针数组
- 例8.28指向指针的指针变量
- 例8.29
指针
在程序中定义一个变量时,系统会为该变量创建一个存储单元。存储单元的编号被称为地址。程序可以通过地址找到变量,即地址指向变量,因此C语言中将地址形象的称为“指针”。
指针说明了变量的位置信息,但无法确定该变量占用了多少个存储单元。因此若是要有效地存取一个数据,除了需要指针(即位置信息)外,还需要该数据的类型信息,即数据类型。综上所述,C语言中的地址包括位置信息和类型信息两部分,可以称其为“带类型的地址”。
如:a为整型变量,&a一般称它为“变量a的地址”,确切的说,它是“整型变量a的地址”,一般简称“地址”。
直接访问与间接访问
- 直接访问
通过变量名进行的访问,称为“直接访问”
如:
int a = 3;
- 间接访问
将变量i的地址存放在另一变量中,然后通过该变量来找到变量i的地址,从而访问变量i。这类专门存放另一个变量的地址的变量,称为“指针变量”。指针变量的值是地址。
指针变量
指针变量是专门用来存放变量的地址(即指针)的变量。指针变量的值是地址。
定义指针变量
定义指针变量的一般形式为:
类型名 * 指针变量名;
一个变量的指针的含义包含两个方面:一是以存储单元编号表示的纯地址;二是它指向的存储单元的数据类型;指向整型数据的指针类型表示为“int *”,读作“指向int的指针”或简称“int 指针”。
例如:
int * pointer_1, * pointer_2;
引用指针变量
- 给指针变量赋值:
p = &a; //把a的地址赋给指针变量p
- 引用指针变量指向的变量
* p = 1; //将整数1赋给p当前所指向的变量
printf("%d", * p); //输出指针变量p所指向的变量的值
运算符 | 说明 |
---|---|
& | 取地址符,&a是变量a的地址 |
* | 指针运算符,* p代表指针变量p指向的对象 |
指针变量作为函数参数
指针变量作为函数参数,它的作用是将一个变量的地址传送给另一个函数中。可实现,通过调用函数使变量的值发生变化。
见例8.3
为了使函数中改变了的变量值能被主函数所用,应该用指针变量作为函数参数,在函数的执行过程中使指针变量所指向的变量值发生变化,函数调用结束后,这些变量值的变化依然保留了下来,这样就实现了“通过调用函数使变量的值发生变化”
通过指针引用数组
数组元素的指针就是数组元素的地址,通常数组元素的引用采用下标法(即a[i]),也可以是用指针法,即通过指向数组元素的指针找到所需的元素。
p = &a[0]; //p的值是a[0]的地址
p = a; //与上一句等价,p的值是数组a首元素的地址
数组名其实就是一种指针变量,使用数组名作参数,其实就是传递数组首元素的地址,所以形参其实就是指针变量
如
void fun(int arr[], int n) //arr按指针变量处理,等价于void fun(int * arr, int n){}
{
..........
}
通过指针引用数组元素
-
引用数组元素时指针的运算
当指针指向数组元素时,才会涉及到指针的运算。
若指针已指向数组中的一个元素,则p+1指向同一数组中的下一个元素,p-1指向同一数组中的上一个元素。 -
引用数组元素
- 下标法,如a[i]形式;
- 指针法,如*(a+i)或 *(p+i)。a是数组名,p是指向数组元素的指针变量
使用指针变量直接指向元素,读取速度更快。不必每次都重新计算地址。
通过指针引用多维数组
多维数组
int a[3][4] = {
{
1,3,5,7},{
9,11,13,15},{
17,19,21,23}};
已知a[0]和*(a+0)等价,a[1]和 (a+1)等价,因此a[0]+1与(a+0)+1都是&a[0][1]
字符指针变量和字符数组的比较
- 值不同:字符数组由若干各元素组成,每个元素中放一个字符,而字符指针变量中存放的是地址。
- 赋值方式不同:可以对字符指针变量赋值,但不能对数组名赋值。
- 初始化的含义不同:数组可以在定义时对各元素赋初值,但不能用赋值语句对字符数组中全部元素整体赋值。
如:
char *a;
a = "I love China.";
👆是合规的
```c
char a[];
a[] = "I love China."
👆是不合规的
4. 存储单位的内容不同:编译时为字符数组分配若干存储单元,以存放各元素的值,而对字符指针变量,只分配一个存储单元。
5. 值的改变:指针变量的值时可以改变的,而字符数组名代表一个固定的值,不能改变。
6. 字符数组中各元素的值时可以改变的,但字符指针变量指向的字符串常量中的内容是不可以被取代的。
7. 引用数组元素。数组更方便
8. 用指针变量指向一个格式字符串,可以用它代替printf函数中的格式字符串。
char *format;
format = "a=%d,b=%f\n";
printf(format, a, b);
等价于
printf("a=%d,b=%d\n", a, b);
指向函数的指针
定义指向函数的指针的一般形式为:
*类型名 (指针变量名)(函数参数表列)
指向函数的指针的优势
每次调用函数时给出不同的函数名最为实参即可,调用函数不必作任何修改。这种方法是符合结构化设计方法原则的。
见例8.24
返回指针值的函数
定义返回指针值的函数的原型为
*类型名 函数名(参数列表)
如:
int *a(int x, int y)
{
……
}
*的运算级别较低,a(int x, int y)是一个函数。前面的 int *,说明这是一个指数类型的函数
指针数组
指针数组的每一个元素都是指针,即指针数组的每一个元素都存放了一个地址。
指针数组的定义形式为:
*类型名 数组名[数组长度]
例题汇总
例8.1初识指针
通过指针变量访问整型变量
#include<stdio.h>
int main()
{
int a = 100, b = 10; //整型变量a,b
int * pointer_1, * pointer_2; //指针型变量pointer_1,pointer_2
pointer_1 = &a; //将整型变量a的地址,存入指针变量pointer_1中
pointer_2 = &b; //将整型变量b的指针,存入指针变量pointer_2中
printf("a=%d,b=%d\n", a, b); //输出整型变量的值
printf("pointer_1=%d,pointer_2=%d", * pointer_1, * pointer_2);
//输出指针变量的值,*为取值符号,* pointer_1的意思为地址为pointer_1的整型存储单元中的存储的值
return 0;
}
例8.2引用指针变量(排序)
输入a和b两个整数,按先大后小的顺序输出a和b
#include<stdio.h>
int main()
{
int * p1, * p2, * p, a, b;
printf("请输入两个整数:");
scanf("%d%d", &a, &b);
p1 = &a; //将变量a的地址存入指针变量p1中
p2 = &b; //将变量b的地址存入指针变量p2中
if(a < b) //如果a<b,交换两个指针变量的值。即p1指向较大的数,p2指向较小的数
{
p = p1;
p1 = p2;
p2 = p;
}
printf("a=%d,b=%d\n", a, b); //if语句没有改变a与b的值
printf("max=%d,min=%d\n", * p1, * p2); //指针变量的指向改变了
return 0;
}
例8.3指针变量函数
同例8.2
#include<stdio.h>
int main()
{
void swap(int *p1, int *p2);
int a, b;
int *pointer_1, *pointer_2;
printf("请输入两个整数:");
scanf("%d%d", &a, &b);
pointer_1 = &a;
pointer_2 = &b;
if(a < b)
swap(pointer_1, pointer_2);
printf("最大值为:%d\n最小值为:%d", a, b);
}
void swap(int *p1, int *p2)
{
int temp;
temp = *p1;
*p1 = *p2;
*p2 = temp;
}
/*
若交换函数写成如下则不会实现交换的功能
void swap(int x, int y)
{
int temp;
temp = a;
a = b;
b = temp;
}
执行swap函数后,x和y的值互换了,但并未影响a和b的值。
这是由于函数是“单向传送”的“值传递”,形参的改变不会印象实参的值。
*/
例8.4指针变量函数的错误示范
同例8.2
#include<stdio.h>
int main()
{
void swap(int *p1, int *p2);
int a, b;
int *pointer_1, *pointer_2;
printf("请输入两个整数:");
scanf("%d%d", &a, &b);
pointer_1 = &a;
pointer_2 = &b;
if(a < b)
swap(pointer_1, pointer_2);
printf("最大值为:%d\n最小值为:%d", *pointer_1, *pointer_2);
return 0;
}
void swap(int *p1, int *p2) //swap函数,交换p1与p2的指向
{
int *p;
p = p1;
p1 = p2;
p2 = p;
}
C语言中实参变量和形参变量之间的数据传递是单向的值传递方式,用指针变量作函数参数时同样要遵循这一规则。不可能通过执行调用函数来改变实参指针变量的值,但是可以改变实参指针变量所指变量的值。
例8.5
输入3个整数a,b,c要求按由大到小的顺序将它们输出。
#include<stdio.h>
int main()
{
void exchange(int *q1, int *q2, int *q3); //函数声明,由大到小排列
int a, b, c, *p1, *p2, *p3;
printf("请输入3个整数:\n");
scanf