「C 语言」8 征服 C 指针
感谢你,编译器
指针类型(pointer type)
定义
指针类型可由函数类型、对象类型或不完全的类型派生,派生指针类型的类型称为引用类型。
- 先有指针类型
- 所以有了指针类型的变量和指针类型的值
- 这里指针类型的值 几乎指的是内存的地址
操作符
- 对变量使用取地址操作符
&
,可以取得该变量的地址,这个地址称为指向该变量的指针int *p=&a
- 指针变量保存了指向其他变量的地址,可以说p指向了a
- 对指针使用解引用操作符
*
,就等同于它指向的变量,*p
等于a
关于
*
的位置:靠近变量名
int *a, b
VSint* a, b
指针运算
对于指针的加减运算,标准只允许 指针指向数组内的元素,或者超过数组长度的下一个元素
- 对指针+1,地址的值会 增加当前指针所指向数据类型的长度
空指针
NULL——指向$\varnothing$
#define NULL 0
—— 0 在上下文中可以被识别为空指针如
int *p = 0
#define NULL ((void*)0)
SWAP
void swap(int *a, int *b){
int tmp = *a;
*a = *b;
*b = tmp;
}
swap(&a, &b);
仅仅交换整形变量的值,可以不使用临时变量
#define SWAP(a, b) (a += b, b = a - b, a -= b)
!!!但是在
SWAP(a[i], a[i])
的情况下不可以
数组
在 C 中,如果在数组名后不加
[]
,单独地只写数组名,那么此名称就表示「指向数组初始元素的指针」。
以上说法是错的
//p = &array[0];
p = array;
for (i = 0; i < 5; i++) {
printf("%d\n", *(p + i));
}
*(p + i)
和 p[i]
是等价的
所以不如
for (i = 0; i < 5; i++) {
printf("%d\n", array[i]);
}
p[i]
是*(p + i)
的简便写法。所以可以写成i[p]
- 下标运算符
[]
原本只有这种用法,它和数组无关。
函数的参数传递
不要滥用指针运算
void strcpy(char *s, char *t)
{
while ((*s++ = *t++)!='\0')
;
}
上面的while语句,前面的表达式——赋值语句返回左操作数
但是循环结束后,指针指向了空字符的下一个字符(容易引发bug)
不要修改传入的参数
数组作为函数参数
如果试图将数组作为函数参数进行传递,那就传递指向初始元素的指针。
无论如何都要将数组进行值传递的时候,建议将数组整体整理成结构体成员。
一般进行传址调用,在搜索时才会使用传值调用
声明函数形参的方法
int fn(int *a)
和 int fn(int a[])
只有在声明函数形参时,数组的声明才可以被解读成指针(定义了元素个数是无用的)
int fn(int *a);
int fn(int a[]);
int fn(int a[10]);
内存地址
如今的操作系统会给每一个进程分配独立的「虚拟地址空间」