前言
正文
指针
在C语言中,内存单元的地址称为指针。
专门用来存放地址的变量,称为指针变量。
存储类型 数据类型 * 指针变量名;
int a = 10; # 第一种 int *p = &a; # 第二种 int *p; //默认有个地址,不知道赋值了什么 p = &a;
NULL指针
NULL指针是一个特殊的指针变量,表示不指向任何东西。
要使一个指针变量为NULL,直接赋值给他一个零值即可。为了测试一个指针变量是否为NULL,可以将它与零值进行比较。
对一个NULL指针进行解引用操作时非法的。因此,对指针进行解引用之前,需要进程非NULL指针判断。
//初始化时就指向NULL指针,要不然是个野指针 char *p = NULL; char str[] = "@站长"; //指向str p = str; //下面两种都可以判断是否p为NULL指针 if (NULL != p) { printf("p = %s\n", p); } if (p) { printf("p = %s\n", p); }
指针运算
如果p指向的char的指针,那么表达式p+1就是指向下一个char,偏移1*1个字节(char占一个字节)。
如果p指向的float的指针,那么表达式p+1就是指向下一个float,偏移1*4个字节(假设float占4个字节)。
*p指针占用大小,跟什么类型指针有关系
表达式 p指向的类型的指针 *p指针占用大小 指针偏移的字节 p+1 char 1 1*1 p+1 short 2 1*2 p+1 int 4 1*4 p+1 double 8 1*8 p+2 char 1 2*1 p+2 short 2 2*2 p+2 int 4 2*4 p+2 double 8 2*8
指针和字符串
字符串在C语言中基石char类型的数组。
char *p = null; char buffer[]= "abcdef"; # p 指向buffer,就是buffer[0]的地址 p = buffer;
-
给p赋值只会改变指针变量的值,不会改变指针的内容
# 指针变量+1,其实就是便宜一个char位置 # 此时p指向了buffer[1] p=p+1; # 或 p++;
-
给*p 赋值,不会改变指针变量的值,只会改变指针指向的内存块的值。
# 就是p指向buffer, 也就是buffer[0]的地址 p = buffer; # 因此,就是buffer[0] = '0'; *p = '0';
-
= 左边*p表示是给内存块复制, = 右边的表示取值。
# 改变p指向地址的存储值 # 等同于buffer[0] = '3'; *p = '3'; # 获取存在p中的地址中的值 # a = buffer[0] char a = *p;
二级指针
把一个指向[指针变量]的指针变量,称为二级指针变量。
二级指针是比较常见的,至于三级或四级几乎很少见!
一般格式
存储类型 数据类型 ** 指针名;
举个例子
int a = 10; # 一级指针 int *p; # 二级指针 int **q; # 存储a的地址 p= &a ; # 存储p的地址 q= &p;
void指针
void指针是一种数据类型不明确的指针变量,它可以通过强制类型转换,让该类型指向任何数据类型的变量。
一般格式
void * 指针变量
int a= 10; int *p ; p= &a; void * q; q= (void * ) p;
此时q和p都指向a的地址。
指针数组
指针数组是指具有若干个相同存储类型的指针变量构成的组合。
PS: 数组在最后,说明这个是数组!
存储类型是指针。
一般格式
存储类型 数据类型 * 指针数组名 [大小]
//指针数组,类型是int * 所以叫int型指针数组 int * p[n];
[]的优先级比*高,所以p先是一个数组,在int * 组合说明是一个整型指针数组,含有n个指针类型的数组。
int *p[2]; int a[2][3]= {{1,2,3},{4,5,6}}; p[0] = a[0]; //等同于&a[0][0];就是获取a[0]的地址。 #如果后续没有p[1] = a[1],p[1]依旧随机的地址
数组指针
数组指针也就是行指针。存储行地址的指针就行指针变量。
PS:指针在后面,说明这个是指针!
指针是可以指向某个地址的
一般格式
存储类型 数据类型 (*行指针变量)[常量表达式]
比如
# 数组指针 int (*p)[3];
()的优先级比[]高,说明p是一个指针,指向一个整型的一为数组,这个一维数组大小为n。
# 有3行2列的二维数组 int a[3][2]= {{1,2},{3,4},{5, 6}}; # 数组指针 int (*p)[2]; p = a;
指针函数
指针函数是一个函数的返回值为地址的函数。
PS: 函数在后面,说明这个是函数!
返回类型为指针。
一般格式
数据类型 * 函数名(形参){ 语句: }
char name[] = "@站长"; # 返回char类型的指针(就是地址嘛) char* getName() { return name; }
函数指针
函数指针用来存放函数的地址,这个地址就是函数的入口地址。
函数名代表函数的入口地址。
PS:指针在后面,说明这个是指针!
指针是可以指向某个地址的
一般格式
数据类型 (* 函数指针名称) (参数说明表);
规则
-
数据类型 : 是函指针所指向的函数返回值类型
-
参数说明表 : 与函数指针缩指向的形参说明表保持一致`
# 定义 int (*fun_sum)(int x, int y); int sum(int x, int y){ return x+y; } # 指向sum # 可看成给sum函数找新代理名为fun_sum fun_sum = sum;
const指针
#第一种 int const *p; # 第二种 int * const p; # 第三种 int const * const p;
第一种
const修饰的是 *p,也就是,你可以修改p的指向地址,但不能修改p所指向地址的值。
int a = 10; int b = 200; int const *p = &a; # 正确 p = &b; # 错误,不可以修改p指向地址的值 *p = 300;
第二种
const修饰的是p,也就是,你可以修改p所指向地址中的值,但不可以修改p的指向地址。
int a = 10; int b = 200; int * const p = &a; # 错误,不可以修改p的指向 p = &b; # 正确,可以修改p指向地址的值 *p = 300;
第三中
有两个const修饰,也就是,你不可修改所指向的指向,也不可以修改指向地址中的值。
真正的常量!
int a = 10; int b = 200; int const * const p = &a; # 错误 p = &b; # 错误 *p = 300;
参考文章
-
《》
-
《