11 指针

字节(byte):大多数现代计算机用字节来分割内存,每个字节可以存储8位信息。每个字节都有唯一的地址,用来和内存中的其他字节进行区别。
变量在内存中的地址:程序中的每个变量占有一个或多个内存字节,把第一个字节的地址称为变量的地址。
指针变量:(pointer variable)虽然可以用整数表示地址,但是其取值单位可能不同于整数的范围,所以一定不能用普通整型变量存储地址。但是,可以用指针变量存储地址。
指针:在用指针变量 p 存储变量 i 的地址时,我们说成是 p 指向 i 。换句话说,指针就是地址,而且指针变量是只存储地址的变量。

11.1声明指针变量

语法: int *p

  • 必须在指针变量名字前放置*
  • 可以和其他变量一起出现在声明中
  • 每个指针变量唯一指向特定类型(引用类型)的对象
  • 对指针可以指向的引用类型没有限制,甚至可以指向另一个指针。
1
int i, i, a[10], *p;

11.2 取地址运算符和间接寻址运算符

运算符 名称 说明
&变量 取地址运算符 找到变量的地址
*指针变量 间接寻址运算符 找到指针指向的对象

11.2.1 取地址运算符

先声明后赋值:

1
2
int i, *p;
p = &i;

声明的同时赋值:

1
int i, *p = &i;

11.2.2 间接寻址运算符

说明:一旦指针变量指向了对象,就可以使用*运算符访问存储在对象中的内容。

1
2
int i, *p = &i;
printf("%d\n", *p);//*p等价于i

注意:不要把间接寻址运算符用于未初始化的指针变量。否则一旦改变未知的内存单元可能会导致不规律的行为或操作系统的崩溃。

11.3 指针赋值

前提:两个指针具有相同的类型

1
2
3
int i, j, *p, *q;
p = &i;
q = p;//把i的地址右赋值给了p,此时有两个指针同时指向i

11.4 指针作为实际参数

背景:c语言的参数传递机制为“值传递”,参数传递进来的是变量的副本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int int_part;
float frace_part;

/*声明*/
void decompose(float x, int *int_part, float *frac_part);
//或void decompose(float x, int *, float *);
decompose(3.1415926, &i, &f);
/*调用*/

/*定义*/
/**
* 取出一个浮点数的整数部分和小数部并分别赋值给两个外部变量
* @param x 目标浮点数
* @param *int_part 存储整数部分的地址
* @param *fract_part 存储小数部分的变量
*/

void decompose(float x, int *int_part, float *fract_part){
*int_part = (int) x;
*fract_part = x - *int_part;
}

11.4.1 程序:找出数组中的最大元素和最小元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/**
* Finds the largest and smallest elements in an array
*/

#include <stdio.h>

#define N 10
void max_min(int a[], int n, int *max, int *min);

int main(){
int b[N], i, big, small;

printf("Enter %d numbers:", N);
for(i = 0; i < N; i++){
scanf("%d", &b[i]);
}
max_min(b, N, &big, &small);
printf("Largest: %d\n", big);
printf("smallest: %d\n", small);

return 0;
}

/**
* 找出最大值和最小值并将结果赋给响应指针对应的变量
* @param a 数组
* @param n 数组大小
* @param max 存储最大值的变量
* @param min 存储最小值的变量
*/

void max_min(int a[], int n, int *max, int *min){
int i;
*max = *min = a[0];
for(i = 1; i < n; i++){
if(a[i] > *max){
*max = a[i];
}else if(a[i] < *min){
*min = a[i];
}
}
}
1
2
3
4
$ ./maxmin 
Enter 10 numbers:1 2 3 4 5 6 7 8 9 10
Largest: 10
smallest: 1

11.4.2 用const保护实际参数

使用指针替代变量副本:如果需要大量的存储空间,那么传递变量的值可能浪费时间和空间。
const:放在形式参数的类型说明之前,证明函数不会改变传递给函数的指针所指向的对象。试图改变用const修饰的形参对应的实参会引发编译器发出特定消息。

11.5 指针作为返回值

用途:函数返回结果的内存位置而不是返回值。
场景:

  1. 返回指向外部变量的指针
  2. 返回声明为static的局部变量的指针
  3. 限制:永远不会返回指向自动局部变量的指针,因为函数返回后局部变量的存储空间就不存在了。
1
2
3
4
5
6
7
8
9
10
int *max(int *a, int *b){
if(*a > *b){
return a;
}else{
return b;
}
}

int *p, x, y;
p = max(*x, &y);