滴水逆向 02-26 指针1
先抛去指针是存地址的这个概念,看看这种类型最本质的特点
“带*类型” 的特征探测
-
宽度
对于一个变量来说,最重要的一个特征就是数据的宽度,如何探测某个类型的变量的宽度?
对于平时用的类型:1
2
3
4
5
6
7
8
9void Test() {
char x;
short y;
int z;
x = 1;
y = 2;
z = 3;
}可见虽然申请空间的时候都是按 4 字节申请的,但是使用起来还是会按照类型本身的宽度去用

但是如果是 * 类型的:1
2
3
4
5
6
7
8
9void Test() {
char* x;
short* y;
int* z;
x = (char*)1;
y = (short*)2;
z = (int*)3;
}发现 * 类型虽然在汇编上没有明确特征,但是不管原本是什么类型,只要加了 * 宽度就全是 4 字节的(不管一个还是两个还是很多个 *)

-
声明
- 带有 * 的类型变量的标准写法:
变量类型* 变量名,这样比把 * 写在变量名前更清晰 - 任何类型都可以带 *,加上 * 以后是新的类型
- *可以是任意多个
- 带有 * 的类型变量的标准写法:
-
赋值

- 带 * 类型的变量赋值时只能使用“完整写法”
- 带 * 类型的变量宽度永远是 4 字节、无论类型是什么,无论有几个 *
-
++ – 操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15void Test() {
char* a;
short* b;
int* c;
a = (char*)100;
b = (short*)100;
c = (int*)100;
a++;
b++;
c++;
printf("%d %d %d\n", a, b, c); //101 102 104
}发现 ++ 过后,加的是 * 前类型本身的宽度,汇编里也是这样的直接
add 1/2/4的,但是如果是 ** 呢?会发现输出变了1
2
3
4
5
6
7
8
9
10
11
12
13
14
15void Test() {
char** a;
short** b;
int** c;
a = (char**)100;
b = (short**)100;
c = (int**)100;
a++;
b++;
c++;
printf("%d %d %d\n", a, b, c); //104 104 104
}一个公式:去掉一个 * 后的宽度,就是 ++/-- 要加几或减几
总结:
- 不带 * 类型的变量,++/-- 都是加1或减1
- 带 * 类型的变量,++/-- 新增/减少的数量是去掉一个 * 后变量的宽度
-
加上/减去一个整数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15void Test() {
char* a;
short* b;
int* c;
a = (char*)100;
b = (short*)100;
c = (int*)100;
a = a + 5;
b = b + 5;
c = c + 5;
printf("%d %d %d\n", a, b, c); //105 110 120
}和 ++/-- 本质一样,加 n 的话,增加的就是 * 的数量砍掉一个后 *n 的宽度。同理,如果是一串 * 那么上面代码例子的输出就会是三个 120
总结:
- 带 * 类型的变量可以加、减一个整数,但不能乘或者除
- 带 * 类型变量与其他整数相加或相减时:
- 带 * 类型变量 + N = 带 * 类型变量 + N * (去掉一个 * 后类型的宽度)
- 带 * 类型变量 - N = 带 * 类型变量 - N * (去掉一个 * 后类型的宽度)
-
求差值
1
2
3
4
5
6
7
8
9
10
11void Test() {
char* a;
char* b;
a = (char*)200;
b = (char*)100;
int x = a - b;
printf("%d\n", x); //100
}但是如果是 2 个 * 呢?
1
2
3
4
5
6
7
8
9
10
11void Test() {
char** a;
char** b;
a = (char**)200;
b = (char**)100;
int x = a - b;
printf("%d\n", x); //25
}总结:
- 两个类型相同的带 * 类型的变量可以进行减法操作
- 相减的结果要除以砍掉一个 * 的数据的宽度
-
比较
1
2
3
4
5
6
7
8
9
10
11
12
13void Test() {
char**** a;
char**** b;
a = (char****)200;
b = (char****)100;
if (a > b) { //1
printf("1");
} else {
printf("2");
}
}总结:
- 带 * 的变量,如果类型相同,可以做大小的比较
课后作业
-
char类型占几字节?char*类型占几字节?int*****占几字节?
如图,分别占 1、4、4 字节

-
char** arr[10]占多少个字节?
4*10 = 40 字节 -
自定义结构体如下:
1
2
3
4struct Student {
int x;
int y;
};第一步:
1
2
3
4
5
6
7
8
9void test() {
Student**** s;
s = (Student****)100;
s++; //100+4=104
s = s + 2; //104+4*2=112
s = s - 3; //112-4*3=100
}第二步:
1
2
3
4
5
6
7
8
9
10void test() {
Student**** s1;
Student**** s2;
int x;
s1 = (Student****)200;
s2 = (Student****)100;
x = s1 - s2; //(200-100)/4=25
}第三步:
1
2
3
4
5
6
7
8
9void test() {
Student* s;
s = (Student*)100;
s++; //100+8=108
s = s + 2; //108+8*2=124
s = s - 3; //124-8*3=100
}第四步:
1
2
3
4
5
6
7
8
9
10void test() {
Student* s1;
Student* s2;
int x;
s1 = (Student*)200;
s2 = (Student*)100;
x = s1 - s2; //(200-100)/8=12.5=12
}