指针
-
变量与地址:指针就是地址,变量是某一块空间的抽象表示。指针变量保存了地址值;指针变量的类型描述了其读取或偏移的空间大小。
-
指针与指针变量:指针可以理解为一个地址;指针变量就是存放一个地址的变量。
-
指针与字符数组:使用时注意操作的是指针变量还是字符串常量。
-
空指针与野指针:野指针,当前指针指向的内容是不确定的。空指针,int* p = NULL;
-
空类型:void 可以赋给任意类型的指针,任意类型的指针也可以赋值给 void;在不确定需要什么样的数据类型时可以使用该类型;特殊情况void* 和函数指针(指针函数?)的相互赋值未定义。
-
指针运算:&(取地址)、*(取值)、关系运算(比较连续地址的高低)、+ -(地址偏移,+1指的是+1个所指类型的大小)
-
指针的类型决定了偏移读取的空间大小
直接访问与间接访问:
不同类型指针的意义
// 对于所有的指针类型变量的大小都是固定的 8 (当前测试环境,非所有环境)
char* c;
int* n;
double* d;
int** p;
double** q;
printf("%zu\n", sizeof(c));
printf("%zu\n", sizeof(n));
printf("%zu\n", sizeof(d));
printf("%zu\n", sizeof(p));
printf("%zu\n", sizeof(q));
/*
--- 执行结果 ---
8
8
8
8
8
*/
// 不同类型指针的意义在于取出保存地址值的区别
// int* p; *p 时将读取一个 int 的大小;
// double* q; *q 时将读取一个 double 的大小
// char* c; *c 时将读取一个 char 的大小;
// 以此类推
指针与一维数组
// arr是地址常量,不可以进行自增自减运算
int arr[3] = { 1, 2, 3 };
// p是指针变量,可以自增自减运算
int* p = arr;
p += 1; // 地址发生偏移,p指向改变
p + 1; // p本身指向没变
指针与二维数组,数组指针
#define N 2
int main(void)
{
int i = 0, j = 0;
int arr[N][N] = { 1, 2, 3 };
int(*p)[N] = arr; // 数组指针,每次偏移[N]
printf("%p\n", p); // 指针类型为数组,偏移一个一维数组
printf("%p\n", p + 1);
printf("%p\n", *p); // 指针类型为int,偏移一个int
printf("%p\n", (*p) + 1);
for (i = 0; i < N; i += 1)
{
for (j = 0; j < N; j += 1)
{
// 调整指针类型,然后偏移取值
printf("%p -> %d\n", *(p + i) + j, *(*(p + i) + j));
}
}
return 0;
}
const与指针
int n = 10;
int const* p = &n; // 常量指针;当前const 限定的是 *p;p可变,n可变
const int *p; // 限定了 int * 即限定了*p不可变。
int* const p = &n; // 指针常量;当前const 限定的是 p;*p可变,n可变;
int* const p; // 限定了变量p,变量p的值不可变。
int const *const p; // 即是常量指针,也是指针常量;限定 *p 和 p;n可变;
const int* const p; // 两个都限定。