指针修饰
1、const常量化
1.1const相当于只读(read-only),被修饰的变量不能被修改,若直接修改则报错
对比:不修改被const修饰的变量,则能输出
a的值不能被更改,但a所在的空间可以修改,也就是通过指针间接修改
const只是修饰变量a,*p没有被修饰,
initialization discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
警告:a被const修饰,把a的地址赋值给指针时,会丢弃const
1.2const修饰指针指向的内容
const int *p;//const修饰*p,指针指向的内容不能修改,指针的指向可以修改,
int a=2;
int b=20;
const int *p=&a;
//*p=20;//错误,*p被修饰,指针指向内容*p不能修改
p=&b;//p的指向可以被修改
1.3直接修饰p int *const p;修饰指针的指向p,指针的指向不能修改,可以更改指向的内容。
指针的指向和指针指向的内容都不能修改:
int const * const p;
-
- void空类型
2.1不能修饰变量:void a;//错误
2.2void可以修饰指针
void *p=NULL;//正确写法
int a=2;
(int*)p=&a;//将指针p强制转换成int.在哪使用在哪强转,
-
- 大小端
计算机里如果存储超过一个字节,会出现存储数据的顺序不同的问题,大小端问题。
大端:低地址存放高字节的数据,高地址存放低字节。(左边高字节,右边低字节)
小端:低地址存放低字节的数据,高地址存放高字节。
存储十六进制0x12345678假设起始地址:0x1000
0x1000 0x1001 0x1002 0x1003
小端:0x78 0x56 0x34 0x12
大段:0x12 0x34 0x56 0x78
结论:电脑小端存储
4、二级指针:
一级指针:存放变量的地址
二级指针:存放一级指针的地址
格式:存储类型 数据类型 **指针变量名
int **q
int a=2;
int *p=&a;
int **q=&p;
访问a的值:a *p
访问a的地址:&a p *q
访问p的地址:&p q
p:&p一级指针的地址,一级指针里存的内容是变量的地址
- 指针与数组
在C语言中,数组的指针是指数组在内存中的起始地址,数组元素的地址是指数组元素在内存中的起始地址
直接访问:通过数组名访问
间接访问:通过指针来访问
地址 | 内容 | 元素 | |||||
p | a | &a[0] | 3 | a[0] | *a | p[0] | *p |
p+1 | a+1 | &a[1] | 4 | a[1] | *a+1 | p[1] | *p+1 |
p+2 | a+2 | &a[2] | 5 | a[2] | *a+2 | p[2] | *p+2 |
p+3 | a+3 | &a[3] | 6 | a[3] | *a+3 | p[3] | *p+3 |
p+4 | a+4 | &a[4] | 7 | a[4] | *a+4 | p[4] | *p+4 |
1、一维数组的数组名为一维数组的指针(起始地址)
例:double x[8]; x为x数组的起始地址。
设指针变量px的地址值等于数组指针x(即指针变量px指向数组的首元数)
则:x[i]、p[i]、*(px+i)、*(x+i)、具有完全相同的功能:访问数组第i+1个数组元素。
访问数组元素a[i]的值:
直接访问:a[i] *(a+i)
间接访问:p[i] *(p+i)
访问元素a[i]的地址
直接访问:&a[i] a+i
间接访问:&p[i] p+i
- 注:指针变量和数组在访问数组中元素时,一定条件下其使用方法具有相同的形式,因为指针变量和数组名都是地址量,但指针变量和数组的指针(或叫数组名)在本质上不同,指针变量是地址变量,而数组的指针是地址常量。
a和p本质不同,a是地址常量,p是变量,a不能执行++操作,不能做赋值运算
运算方法:
1)++和*都是单目运算符,优先级相同
2)单目运算符从右向左运算
(*p)++;//先取p指向的内容,对内容++
*p++;//先执行p++,但是++在后,先取*操作,打印*p,再p++,指针向后移动
++*p;//先执行*p,取变量的值,对值进行++;
++(*p);//先执行*p,取变量的值,对值进行++;
*++p;//先对p指向的地址++,对移动后的地址取内容
- 指针与二维数组
二维数组元素连续存储,按行优先存。
1、使用一级指针遍历二维数组:
a[3][2];//a数组名,第一行首地址,a+1,第二行的首地址。
行 | ||
a[0] | a[0][0] 1 | a[0][1] 2 |
a[1] | a[1][0] 3 | a[1][1] 4 |
a[2] | a[2][0] 5 | a[2][1] 6 |
2、可把二维数组看做由多个一维数组组成
二维数组名代表数组的起始地址,数组名加1,是移动一行元素,
因此,二维数组名常被称为行地址。a[0]、a[1]、
- 行地址加*改变性质,按序输出。
*a;表示把行地址降级为列地址。
*a:第一行第一个地址
*a+1:第一行第二例地址
*(a+1):第二行第一列地址
*(a+1)+1:第二行第二列地址
地址 | 数组 | 元素 | ||||
a[0] | &a[0][0] | *a | 1 | a[0][0] | *(*a) | *a[0] |
a[0]+1 | &a[0][1] | *a+1 | 2 | a[0][1] | *(*a+1) | *(a[0]+1) |
a[1] | &a[1][0] | *(a+1) | 3 | a[1][0] | *(*(a+1)) | *a[1] |
a[1]+1 | &a[1][1] | *(a+1)+1 | 4 | a[1][1] | *(*(a+1)+1) | *(a[1]+1) |
a[2] | &a[2][0] | *(a+2) | 5 | a[2][0] | *(*(a+2)) | *a[2] |
a[2]+1 | &a[2][1] | *(a+2)+1 | 6 | a[2][1] | *(*(a+2)+1) | *(a[2]+1) |
访问数组元素地址a[i][j]:
a[i]+j &a[i][j] *(a+i)+j;
访问数组元素值:
a[i][j] *(a[i]+j) *(*(a+i)+j)
五、数组指针(行指针)
存储行地址的指针变量叫做行指针变量。形式如下:
<存储类型> <数据类型>(*<指针变量名>)[表达式:列数];
例:int a[2][3]; int(*p)[3];
方括号中的常量表达式表示指针加1,移动几个数据。如:int (*p)[2]指针加一移动两个数据
当用行指针操作二维数组时,表达式一般写成1行的元素个数,即列数
例:使用行指针表示二维数组中的某个元素