概念
指针是定义, C/C++中每个变量在内存里都有唯一地址, 该地址也称为指针
指针变量是指针具体实现, 其存储其他变量内存地址, 并可通过变量地址间接访问修改变量
操作
定义
int *p;
char *p;
double *p;
指针变量是变量, 值是所存储变量在内存中地址
取地址
使用&
运算符可获取变量地址, 将地址值赋值给指针变量完成初始化
- 示例, 获取变量地址, 初始化指针变量
graph LR;
subgraph S1[int a]
direction LR
V2(value: 0xFF)-->A2(address: 0x7fff6be9543c)
end
subgraph S2[int* p]
direction LR
V1(value: 0x7fff6be9543c)
end
A2--"&"-->S2
#include <stdio.h>
int main() {
int a = 0xFF;
int *p = &a;
printf("a address: %p\n", &a);
printf("p value: %p\n", p);
return 0;
}
解引用
使用*
运算符可解析该地址对应变量值
- 示例, 获取指针存储变量地址对应值
graph LR;
subgraph S1[int a]
direction LR
V2(value: 0xFF)
A2(address: 0x7fff6be9543c)
A2-->V2
end
subgraph S2[int* p]
direction LR
V1(value: 0x7fff6be9543c)
end
S2--"\*"-->A2
#include <stdio.h>
int main() {
int a = 0xFF;
int *p = &a;
printf("a value: %d\na address: %p\n", a, &a);
printf("p value: %p\n*p value: %d\n", p, *p);
return 0;
}
属性
指针指向(指针值)
指针值是其所存储变量地址, 也称指针指向该变量
- 示例, 初始化指针指向
#include <stdio.h>
int main() {
int a = 10;
// 等价 int *p; p = &a;
int *p = &a;
printf("a = %d, &a = %p\n", a, &a);
printf("*p = %d, p = %p\n", *p, p);
return 0;
}
graph LR;
subgraph S1[int a]
direction LR
V2(value: 10)
A2(address: 0x7fffed97d56c)
end
subgraph S2[int* p]
direction LR
V1(value: 0x7fffed97d56c)
end
V1-->A2
改变指针指向
改变指针值存储新变量地址, 也称改变指针指向
- 示例, 改变指针值
指针变量p原本存储变量a地址, 现让其存储变量b地址, 改变指针指向
#include <stdio.h>
int main() {
int a = 0xFF;
int* p = &a;
printf("p = %p, *p = %d\n", p, *p);
int b = 0xAA;
p = &b;
printf("p = %p, *p = %d\n", p, *p);
return 0;
}
graph LR;
subgraph S1[int a]
direction LR
V2(value: 0xFF)
A2(address: 0x7ffe3ee184b8)
end
subgraph S2[int* p]
V1(value: 0x7ffe3ee184b8)
end
V1--->A2
graph LR;
subgraph S3[int b]
direction LR
V3(value: 0xAA)
A3(address: 0x7ffe3ee184bc)
end
subgraph S2[int* p]
V1(value: 0x7ffe3ee184bc)
end
V1-->A3
改变指针指向值(间接修改变量)
通过指针所存储变量地址, 可间接操作修改变量值
- 示例, 间接修改
指针p存储变量a地址, 通过地址间接修改变量a
#include <stdio.h>
int main() {
int a = 0xFF;
int* p = &a;
printf("a = %d, &a = %p\n",a, &a);
printf("p = %p, *p = %d\n", p, *p);
*p = 0xAA;
printf("p = %p, *p = %d\n", p, *p);
printf("a = %d, &a = %p\n",a, &a);
return 0;
}
graph LR;
subgraph S1[int a]
direction LR
V2(value: 0xFF)
A2(address: 0x7ffd85a743bc)
end
subgraph S2[int* p]
V1(value: 0x7ffd85a743bc)
end
V1-->A2
graph LR;
subgraph S1[int a]
direction LR;
V2(value: 0xAA)
A2(address: 0x7ffd85a743bc)
end
subgraph S2[int* p]
V1(value: 0x7ffd85a743bc)
end
V1-->A2==>V2
类型
指针类型
指针变量去掉变量名
后是指针类型
指针变量 | 指针类型 |
---|---|
int *p1 | int * |
char *p2 | char * |
double **p3 | double ** |
指针变量大小只与系统位数有关, 与类型无关, 因为不论何类型指针都是存储地址值
32位系统指针大小为4字节, 64位系统指针大小位8字节
#include <stdio.h>
int main() {
int* p = NULL;
double* p1 = NULL;
printf("sizeof p = %d\nsizeof p1 = %d\n", sizeof(p), sizeof(p1));
return 0;
}
指针指向类型
指针变量去掉* 变量名
表示指向类型
指针变量 | 指针指向类型 |
---|---|
int *p1 | int |
char *p2 | char |
double **p3 | double * |
指向区域大小
// 指针指向4字节大小区域
int a = 3;
int *p = &a;
// 指针指向1024 字节 大小区域
const int SIZE = 1024;
char *p = (char *)malloc(sizeof(char) * SIZE);
特殊指针
常量指针
常量指针是指针
指向常量(存储常量地址), 指向可变(可存储其他变量), 指向值不可变(不能通过地址间接修改变量值)
const int *p;
指针类型 int *
, 指针指向类型 const int
graph LR;
subgraph S1[const int a]
direction LR
V[value: 不可变]
A[address]
end
subgraph S2[const int* p]
V2[value]
direction LR
end
S2-->A==>V
- 示例, 尝试改变常量指针指向和指向值
#include <stdio.h>
int main(void) {
const int a = -1;
const int b = 1;
const int *p = &a;
printf("%d\n", *p);
// 尝试改变指针指向
p = &b;
printf("%d\n", *p);
// 尝试改变指针指向值, 报错
*p = -1;
printf("%d\n", *p);
return 0;
}
指针常量
指针常量是常量
指针本身是常量(指针是常量类型), 指向不可变(不能再存储其他变量地址), 指向值可变(可通过地址间接修改变量值)
int *const p;
指针类型 int *const
, 指针指向类型 int
graph LR;
subgraph S1[int a]
V[value]
A[address]
end
subgraph S2[int *const p]
direction LR
V2[value: 不可变]
end
S2==绑定==>A
- 示例, 修改指针常量
#include <stdio.h>
int main(void) {
int a = -1;
int *const p = &a;
printf("%d\n", *p);
// 尝试改变指针指向值
*p = 1;
printf("%d\n", *p);
int b = 1;
// 尝试改变指针指向, 报错
p = &b;
printf("%d\n", *p);
return 0;
}
函数指针
指向函数(存储函数地址), 可间接调用函数
返回值 (*)(参数...,)
- 示例, 通过指针间接调用函数
#include <stdio.h>
int GetMax(int x, int y) {
return x > y ? x : y;
}
int main() {
int (*p)(int, int) = NULL;
p = GetMax;
printf("%d\n", p(1, 2));
return 0;
}
指针数组
指针数组是数组, 数组中元素为指针
int *p[3];
指针类型 int *
, 指针指向类型 int
- 示例, 指针数组使用
#include <stdio.h>
int main(void) {
int *p[3];
int a = 1;
int b = 2;
int c = 3;
p[0] = &a;
p[1] = &b;
p[2] = &c;
for (int i = 0; i < 3; i++) {
printf("p[%d] = %d, &p[%d] = %p\n", i, *p[i], i, &p[i]);
}
return 0;
}
对象指针
指针指向一个对象(存储对象地址)
二级指针
二级指针指向指针, 其值是另一个指针地址
类型 **名称;
- 示例, 二级指针使用
graph LR;
subgraph S1[int a]
direction LR
V1(value: 0xFF)
A1(address: 0x7ffeb5102ea4)
end
subgraph S2[int* p]
direction LR
V2(value: 0x7ffeb5102ea4)
A2(address: 0x7ffeb5102ea8)
end
subgraph S3[int** sp]
direction LR
V3(value: 0x7ffeb5102ea8)
end
V3-->A2
V2-->A1
#include <stdio.h>
int main() {
int a = 0xFF;
int *p = &a;
int **sp = &p;
printf("a: %d, &a: %p\n", a, &a);
printf("*p: %d, p: %p, &p: %p\n", *p, p, &p);
printf("**sp: %d, *sp: %p, sp: %p\n", **sp, *sp, sp);
return 0;
}
数组指针
数组指针是指针, 指针指向数组(存储数组首元素地址)
int (*p)[3];
指针类型 int *
, 指针指向类型 int [3]
- 示例, 数组指针使用
graph LR;
subgraph S1["int a[]"]
subgraph A1[a0]
V0["value"]
A0["address"]
end
subgraph A2[a1]
V12["value"]
A12["address"]
end
A0-->A12
end
subgraph S2["int (*p)[]"]
V2[value]
direction LR
end
S2==>A0
#include <stdio.h>
int main(void) {
int a[3] = {1, 2, 3};
int (*p)[3] = &a;
for (int i = 0; i < 3; i++) {
printf("&a[%d] = %p, a[%d] = %d\n", i, &a[i], i, a[i]);
}
for (int i = 0; i < 3; i++) {
printf("(*p + %d) = %p, *(*p + %d) = %d\n", i, (*p + i), i,*(*p + i));
}
return 0;
}