一、基本概念
-
指针:地址就是指针
-
一般形式:
-
地址对应内存中数据的数据类型 * 指针变量名;
int num = 10; int * p = # printf("%p\n", &num); printf("%p\n", p); *p = 20; printf("%d\n", *p); // 20 printf("%d\n", num); // 20 printf("%d\n", sizeof(p)); // 4
-
指针p保存有整型变量num的地址,那么就说指针p指向了num
-
获取变量地址通过取地址符(
&
)获取变量的地址(首地址、低地址、开始地址) -
通过地址(指针)操作所指向的内存,通过寻址符(解引用符)(
*
)找到对应的内存空间,进行相应的读取操作 -
打印地址(指针)时,用
%p
格式转换说明符进行打印,在一些旧的书记或者网上资料中,会使用%d
或者%x
进行地址的打印 -
在32位操作系统上面,指针占用4字节;在16位操作系统上,指针占用2字节;在64位操作系统上,指针占用8个字节
-
在定义一个指针时,如果没有给它赋值,则他的指向是随机的,称为野指针。
int num = 10; int * p; // 野指针 printf("%p\n", p); printf("%d\n", *p);
-
在定义一个指针时,如果没有明确的指向,那么通常会赋值为NULL,表示为空指针。
int num = 10; int * p = NULL; // todo if (p!=NULL) printf("%d\n", *p);
二、指针的运算符
-
&
:取地址符 -
*
:寻址符 -
=
:赋值运算符 -
\>
、<
、>=
、<=
、==
、!=
:关系运算符 -
指针 + 整数
或指针 - 整数
:指针往后 或 往前 移动整数
个指针所指向变量类型的内存大小。通常用于操作数组int num = 10; int * p = # printf("%p\n", p); // 005AFDA0 printf("%p\n", p+1); // 005AFDA4 printf("%p\n", p+2); // 005AFDA8 printf("%p\n", p-1); // 005AFD9C
-
指针 - 指针
:表示两个指针之间存在几个单位元素,通常使用在数组上。
三、多重指针
int num = 10;
int * p1 = #
int ** p2 = &p1;
int *** p3 = &p2;
printf("%d\n", num);//10
printf("%d\n", *p1);//10
printf("%d\n", **p2);//10
printf("%d\n", ***p3);//10
printf("%p\n", &num);//num的地址
printf("%p\n", p1);//num的地址
printf("%p\n", *p2);//num的地址
printf("%p\n", **p3);//num的地址
printf("%p\n", &p1);//p1的地址
printf("%p\n", p2);//p1的地址
printf("%p\n", *p3);//p1的地址
- 不能对一个变量连续取地址,但是可以对一个多重指针连续寻址
四、指针与数组的关系
-
int arr[5] = {11,22,33,44,55} printf("%p\n", arr); // 008FF890 printf("%p\n", &arr[0]); // 008FF890 printf("%p\n", arr + 1); // 008FF894 printf("%p\n", &arr[0] + 1); // 008FF894
-
数组名在数值方面代表
数组首元素的地址
-
int arr[5] = {11,22,33,44,55}; int * p = arr; // &arr[0]; int i; for (i=0; i<5; ++i) { // printf("%d ", arr[i]); // printf("%d ", *(p+i)); // printf("%d ", *(arr+i)); // printf("%d ", *(i+arr)); // printf("%d ", i[arr]); printf("%d ", p[i]); } puts("");
-
如果指针变量指向数组某元素,那么指针变量可以通过下标运算符访问数组元素
-
数组名和指针的区别:
- 区别一:指针变量允许被重新赋值,指向别的内存;数组名不允许被赋值
- 区别二:sizeof(数组名)得到的是数组的字节数;sizeof(指针变量)得到的是指针变量的字节数
- 区别三:&数组名 得到的是数组的地址;&指针变量 得到的是指针变量的地址
int arr[5] = {11,22,33,44,55}; int * p = arr; int num = 10; // p = &num // arr = &num printf("%d\n", sizeof(arr)); // 20 数组的字节数 printf("%d\n", sizeof(p)); // 4 指针p占的字节数 printf("%p\n", arr); // 数组首元素地址 printf("%p\n", &arr); // 数组地址 printf("%p\n", &arr + 1); // 移动一个数组单位 printf("%p\n", &p); // 指针变量p的地址 int arr[5] = {11,22,33,44,55}; int * p = arr; printf("%d\n", *(&arr[2]-1) ); // 22 printf("%d\n", (&arr[2])[-1] ); // 22 printf("%d\n", *(*(&arr+1)-3) ); // 33 // 11 22 33 44 55 __ __ __ __ __ printf("%d\n", (&arr)[1][-3] ); // 33
五、指针与字符串
-
字符串:可以分为两种
- 符串字面值:“hello world!”
- 字符串数组:char str[] = “hello world!”;
-
字符串相关函数:strcpy 、strlen 、strcmp 、strcat
5.1使用二维字符数组来存放多个字符串
-
char arr[5][10] = {"aaaa","bbbb","eeeeee"}; char arr[5][100]; int i, j; for (i=0; i<5; ++i) gets(arr[i]); for (i=0; i<4; ++i) { for (j=0; j<4-i; ++j) { if (strcmp(arr[j], arr[j+1]) > 0) { char temp[100]; strcpy(temp, arr[j]); strcpy(arr[j], arr[j+1]); strcpy(arr[j+1], temp); } } } puts("==============="); for (i=0; i<5; ++i) puts(arr[i]);
5.2使用字符指针数组来存放字符串
-
指针数组:存放指针的数组,就是数组中每一个元素都是一个指针
int * arr[4]; int a=1, b=2, c=3, d=4; arr[0] = &a; arr[1] = &b; arr[2] = &c; arr[3] = &d;
-
数组指针:是一个指针,一个指向数组的指针
int arr[5] = {11,22,33,44,55}; int (* p)[5] = &arr; // p保存着arr数组的地址 printf("%d\n", (*p)[1]); // 22
-
字符指针数组:数组中每一个元素都是一个字符指针
- char * arr[5];
-
再议字符串字面值——字面值 本质是 指向该字面值首地址的指针,
-
字符串字面值会存储在内存常量只读取,只读区只允许读取,不允许写入。
-
(指针数组)如果一个字符串是确定的(固定不变的) 就可以存放在只读区,然后改变指针的指向就可以改变顺序;
-
(指针数组)如果不确定(字符串时动态变化的),就还是使用数组
-
-
而字符串字面值在编码阶段可以看作是一个指向只读区存放字符串的内存区域的字符指针。
-
例如“hello”可以看作是一个指向只读区,存放“hello”的内存的首地址
char * arr[5] = {"zhaosi", "liuneng","xiedajiao", "guangkun", "xiefeiji"}; int i, j; for (i=0; i<5; ++i) puts(arr[i]); puts("=============="); for (i=0; i<4; ++i) { for (j=0; j<4-i; ++j) { if (strcmp(arr[j], arr[j+1]) > 0) { char * temp = arr[j];` arr[j] = arr[j+1]; arr[j+1] = temp; } } } for (i=0; i<5; ++i) puts(arr[i]);
-