简单理解指针
*与&相互作用:*&a实际上就是a变量
- 是C语言的优势,指针也就是地址
定义格式
类型 *指针变量名;或类型* 指针变量名;
说明
- 指针变量的类型是他指向内存单元中存放的数据类型
- 指针变量必须被赋值语句赋值初始化后才能使用,否则,严重的话会死机
- 可初始化为
0,NULL(不指向任何值)或者某个地址 - 指针变量只能接受地址,赋以数据会错误
引用
- 在指针引用前,要定义,赋值,否则,会造成系统混乱
指针运算符
取址符&
- 单目运算符,结合性自左向右.
取内容符*
- 也叫间接引用运算符,结合性自左向右,且*后面只能是指针.
- 指针的值也可以改变,也就是改变指向.
指针的类型
- 不同类型的指针不能相互赋值(虽然没问题)
1 | int* a = NULL; |
如果*a=0,则*b[0]-*b[3]都会变成0
指针类型的转换
void*表示不知道指向什么东西的指针:int *p = &i; void*q = (void*)p;- 并没有改变
p所指的变量类型,而是用不同的眼光通过p去看它所指的变量q此时认为p指向的变量不是int,而是void
- 并没有改变
场景1
利用函数交换数值(也就是说传给主函数多个数值)
1 |
|
场景2
1.函数返回运算状态,指针返回结果
2.当要返回的值多个都是有效的结果时,要分开返回了
*p和p
*p是常量,p是变量
指针与数组
注意:函数参数表的数组其实就是指针
- 以下四种函数原型是等价的
int sum(int *a, int b)int sum(int*, int)int sum(int a[], int b)int sum(int [], int)
数组就是特殊的指针
[]对指针和数组都可以用,同理*也一样
因为
int a[]<==>int *const a=所以这里不能被赋值
如
a = b;//error
一维数组指针
1 | int a[10]; |
在C语言中规定数组名代表数组中的首地址(声明函数的参数不是,他不占实际内存单元)
实际上p=&a[0]与p=a一样
- 但是数组的单元表达的是变量,需要
&取地址- 意思是把数组的首地址赋给p
p+1实际是p+1*d,d代表字节数
综上,引用数组元素的方法有
- 下标法:
a[0]或p[0]; - 指针法:
*(a+i)或者*(p+i);
a是数组的首地址,即指针常量
- 因为数组元素也是内存变量,所以此类指针的定义和使用和指向变量的指针变量相同.
1 | int a[10] *p; |
- 此时
p指向a[0],下面可以用p表示数组元素.- 下标表示:
1 | p[0],p[1],...//需要定义指针数组 |
- 指针表示法:
1 | *(p+0),... |
- 注意:使用指针变量引用数据时,必须关注当前值
- 比如:若
p=p+3,则p[0]代表a[4]
- 比如:若
二维数组指针
1 | int a[3][4]; |
a是首地址三个行元素的地址分别是:
a,a+1,a+2且a[0],a[1],a[2]也是地址量,即*(a+0),*(a+1),*(a+2)是一维数组的首个元素的地址
每个元素的地址&a[i][j],a[i]+j,*(a+i)+j都可以表示
元素的表示a[i][j],*(a[i]+j),*(*(a+i)+j)可以表示
要使用这两种方法引用元素的前提是二维数组全赋给指针数组
1
2 int (*p)[3], a[2][3];
p = a;注意:
()不能去掉,因为[ ]的优先级高于()
- 意思是一个指向二维数组的指针,只占int的字节数
type *p[num]的意思是一组指针,每个元素保存一个指针
- 等价关系
a+i == p+ia[i] == p[i] == *(a+i) == *(p+i)a[i][j] == p[i][j] == *(a[i]+j) == *(p[i]+j) == *(*(a+i)+j) == *(*(p+i)+j)
说明:
- 赋给指针时首地址是
a[0],**a表示a[0][0]
初始化的方法
方法一
1 | char a[] = {0,1,3,4,5,6,7,8,9,-1}; |
方法二
1 | char a[] = {0,1,3,4,5,6,7,8,9,-1}; |
错误表达
1 | char a[] = {0,1,3,4,5,6,7,8,9,-1}; |
算术操作及比较
只可以作加减法
p+n指的是p指向的数据单元之后的第n个数据单元int *p;(设p的初始值是2000)p+1;表示2002
指针值的比较(
<,<=,>,>=,==,!=)前提条件:
p1和p2是同一类型的指针变量,并且都指向同一段连续的储存空间则
p1<p2为真的话结果是1,否则是0
数组是递增排列的,
a[0]>a[1]
CONST
1.只有C99以后的支持
1 | int * const q = &a; |
- 此时
q被固定,q++不能实现;
1 | const int *q = &a; |
q可以被赋地址,但*q不能被赋值
2.非const转换为const
1 | 针void f(const int* x); |
- 适用于传递的参数类型比地址大时
3.const数组
1 | const int a[] = {1,2,3}; |
此时每个单元都是const,
只能通过初始化赋值,
因为把数组传入函数时是地址,所以函数可以修改数组的值
为了保护数组不被破环,可以设置参数为
const
1 | int sum(const int a[ ] ); |
0地址
通常
0地址不能乱碰你的指针不应该有0值
0地址可以来表示特殊的事情- 返回的指针是无效的
- 指针没有真正初始化
NULL是一个预定的符号,表示0地址一般用
NULL表示0地址
作用
传入较大的数据时用作参数
传入数组后对数组进行操作
返回多个结果
- 修改多个变量
动态申请内存