0x00 数组指针
一个变量有地址,一个数组包含若干个元素,每个数组元素都有相应的地址(数组元素的指针地址是连续的)。比如:int arr[10]
数组名不代表整个数组的地址,数组名代表首元素的地址,arr == &arr[0]
答案是ture。
在使用指针指向数组元素时,允许进行加法(加常量)、减法(减常量)、自增、自减运算。
int arr[5] = {1, 10, 20, -10, 5};int *p = arr; //等价于 = &arr[0];printf("p = %p\n", p); //输出p的值printf("p + 1 = %p\n", p+1); //输出arr[1]的地址,等价于 &arr[1];printf("arr[1] = %d\n", *(p+1)); //输出arr[1]的值printf("arr[1] = %d\n", *p++); //输出arr[1]的值
数组指针进行运算的时候可能会有超过数组元素的情况,比如:数组元素是5个,输出*(p+10)
的值,这样写不会报错,可以正常输出该地址的值。数组名也可以像指针变量一样进行加法、减法运算,但是不能自增、自减。
指针相减
两个指针相减所得之差是两个指针所指数组元素之间相差的元素个数。(地址值 - 地址值)/ sizeof(指针类型)
。两个指针变量之间不能有加法运算(没有意义)。
常见用法(两个指针指向同一个数组):
- 判断两个指针变量指向的元素是否连续
- 判断两个指针变量之间相隔几个元素
指针的关系运算
两个指针可以比较大小,p > p1
这样的写法是没有错的。p1在高位返回为1,否则返回0。
0x01 指针数组
在C语言和C++语言中,数组元素全为指针的数组称为指针数组。——
指针数组一般的定义方法为: 类型说明符 *数组名[数组长度]
int a = 10, b = 2, c = 5;int *pa[3] = {&a, &b ,&c};printf("pa = %p\n", pa); //pa = &pa[0] 数组名为数组的首元素地址printf("pa[0] = %p\n", &pa[0]);printf("a = %d\n"; **pa); //**p等价于*pa[0]int a1[2][2] = {1, 2, 3, 4};int *pa1[2] = {a1[0], a1[1]};printf("**pa1 = %d\n", **pa1); //输出结果为1,pa1 = &pa1[0]printf("**(pa1 + 1) = %d\n", **(pa1 +1)); //pa1 + 1 = pa1[1],pa1[1]的值为a1[1],所以结果是3
题外话:指针数组很绕,绕两圈我已经晕了...
0x02 指针与二维数组
数组名为数组首元素的地址。可以利用数组名来方便的访问到二维数组的各个元素,如图:
使用指针的方式与数组名的方式有些许不同。以下为遍历二维数组代码:
int a[3][4] = { {1,3,5,7},{9,11,13,15},{17,19,21,23}};int *p;for(p = a[0]; p < a[0] + 12; p++){ if((p - 0 % 4 == 0)) printf("\n"); print("%d", *p);}
二维数组抽象出来类似一个表格,在内存里面的存储结构还是一段连续的内存。所以用用指针的方式来遍历二维数组跟遍历一维数组相差不大。
0x03 二维数组指针
二维数组指针的定义方式为:数据类型 (*指针变量名)[二维数组列数]
,指针所保存的内容为二维数组的行指针(行首元素地址)。
int a[3][4] = { {1,3,5,7},{9,11,13,15},{17,19,21,23}};int (*p)[4] = a; //二维数组的初始化for(int i = 0; i < 3; i++){ for(int j = 0; j < 4; j++) { printf("%d\t", *(*(p + i) + j)); } printf("\n");}
0x04 字符串指针
字符串指针定义方式char *指针名 = "字符串内容"
,它的定义方式跟字符指针差不多,区别在于赋值时候给予的是字符('
)还是字符串("
)。
char c = 'a';char *p1 = &c; //定义字符指针char *p2 = "Hello World!"; //定义字符串指针p2 = "I'm Haijun!" //更改字符串指针的指向
字符串指针存储的是该字符串的首地址。
char *str;scanf("%s", str); //这样写会报错,因为str没有分配内存,它是一个野指针,如果 str = malloc(20); 分配内存之后,这样写就没错。
字符串指针与字符数组区别:
- 字符串指针不能直接更改字符串值,只能重新指向;字符数组可以。
- 字符串指针存储在常量区(只读);字符数组存储在栈区。
- 字符串指针赋值方式直接使用变量名(更改指向);字符数组只能在初始化时赋值整个字符串。
0x05 函数指针
在C语言中,一个函数总是占用一段连续的内存区,而函数名就是该函数所占内存区的首地址。我们可以把函数的这个首地址赋予一个指针变量,然后通过这个指针变量就可以找到并调用这个函数,我们把这种指向函数的指针变量称为“函数指针变量”。
函数指针的定义方法:类型说明符 (*指针变量名)(形参,形参,...);
类型说明符表示哈数的返回值。
int sum(int a, int b){ return a + b;}int main(){ int (*p)sum(int, int); //定义函数指针 p = sum; //函数指针指向函数sum int s = p(12, 20); //调用函数指针}
0x06 总结
学了半天的指针,中途也被绕晕过几次,到现在还有一个困惑,指针数组和数组指正什么的到底是为了解决什么问题,一般应用于哪些地方?用法倒是学会了,并不知道有什么用,这也是很纠结的问题...