C语言 day7
指针
指针变量的强制类型转换
案例:
1 |
|
需求:取出如图 橙色框框内的 0x0203
- 如果跨度与宽度不等时,需要用到类型转换
- 观察需求的跨度与宽度
- 选择min(跨度,宽度) 定义指针变量
-
方法一:
运行结果:1
2
3
4
5
6
7
8
int main(int argc,char *argv[]){
int num = 0x01020304;
char *p;
p = #
printf("%#x",*(short *)(p + 1));
return 0;
}
分析:定义的char *p
,指向的变量类型为char
跨度为1字节,宽度为1字节,p+1
跨1个字节,(short *)(p + 1)
跨一个字节后强制类型转换将指针变量p
指向变量类型转换成了short
宽度为2字节,所以取出2个字节。
1 |
|
运行结果:
分析:定义的 short *p
,跨度、宽度都为2字节,先强制类型转换 (char *)(p)
将指针变量指向类型转换为 char
此时的跨度为1字节,然后((char *)(p) + 1)
加一,跨一个字节,(short *)
再强制类型转换将指针p
指向short
,此时的宽度为2字节,取空间内容即可得到0x0203
-
方法三:
定义两个指针变量,一个用来当跨度,一个用来当宽度运行结果:1
2
3
4
5
6
7
8
9
10
int main(int argc,char *argv[]){
int num = 0x01020304;
short *p1;
char *p2;
p2 = #
p1 = p2 + 1;
printf("%#x",*p1);
return 0;
}
分析:定义了两个指针变量,一个用来当跨度,一个用来当宽度,不好描述,自己领悟好了
指针变量的初始化
1. 如果局部指针变量,不初始化,保存的是随机的地址编号(千万不要操作哦)
1 |
|
运行结果:printf("---------222---------");
这个语句并没有执行(段错误),非法内存无法访问
2. 不想让指针变量指向任何地方(也千万不要操作哦)
1 |
|
运行结果:
一样的会出现段错误
3. 将指针变量初始化为合法地址(可以操作)
1 |
|
总结:
1. 指针变量初始化为 NULL
1 | int *p = NULL;//不要对p进行*p操作,容易出段错误 |
2. 指针变量初始化为 合法地址空间
1 | int num = 10; |
& 取地址符 和 * 指针解引用符 的区别(使用中)
引入:
1 |
|
上面代码中的 num
是 int
类型,这个是肯定的,那么请问 &num
是什么类型?… 是 int *
类型。
总结:如果对一个变量取地址 整个表达式类型 就是变量的类型加 *
问1:
1
2int *p;
&p是什么类型? 是int类型问2:
1
2int ****p;
&p是什么类型 是int ***类型问3:
1
2
3
4
5int num = 10;
int *p;
p = #
p是什么类型 是int *类型
所以p = #这个赋值语句左右两边类型是相同的,是严谨的赋值语句问3:
1
2
3
4
5int num = 10;
int *p;
p = #
在使用中,*p是是什么类型?
是int,*p取得是对应地址的空间的内容总结:如果对指针变量取
*
整个表达式的类型是 指针变量的类型减*
总结:如果 & 和 * 同时存在可以相互抵消(从右至左抵消)。(重要)
1 | &*&*&num == # |
指针的注意事项
1.void 不能定义变量
1 | void num;//错误的 系统不知道num的内存大小,无法分配内存空间 |
2.void * 可以定义变量
1 | void *p;//p的类型为void *,而指针类型在32为平台都是4字节,系统知道给p开辟4字节的空间 |
-
p 叫万能指针 p 可以保存 任意一级指针 ,如果是 void **p 就可以保存 任意二级指针···
-
对于 p 不能直接 *p 因为他指向的类型为void,就没办法确定指针的宽度和跨度
1
2
3
4
5
6
7
8
9
10
11
int main(int argc, char* argv[]) {
void* p;
int num = 10;
p = #
// printf("%d\n",*p);
printf("%#x\n", p);
//printf("%#x\n", p + 1);
return 0;
}所以第六行代码编译直接报错,而第八行代码的跨度按道理也是错误的。但是有的编译器编译成功并且跨度当做1字节计算(如DEV C++);在Visual Studio 2019下直接报错。
-
如果要使用的话,就必须进行强制类型转换
1
2
3
4
5
6
7
8
9
10
11
int main(int argc, char* argv[]) {
void* p;
int num = 10;
p = #
printf("%d\n",*(int *)(p));
printf("%#x\n", p);
printf("%#x\n", ((int *)(p) + 1));// p临时指向的类型为int
//printf("%#x\n", p+1);//这里仍然会报错,因为上面的强制类型转换只是临时性的
return 0;
}运行结果:
3. 不要操作 没有初始化的指针变量 即对其取 *
1 | int *p; |
4. 不要操作 初始化为NULL的指针变量 即对其取 *
1 | int *p = NULL; |
5. 不要给指针变量赋无意义的普通数值
1 | int *p = 2000; |
内存必须申请后才能使用,通过人为调用函数申请、定义一个变量系统自动申请空间等等,这些都是合法空间;否则其他的都是非法空间,都不能使用,系统会保护的。
6. 指针变量不要操作越界的空间
1 | char num = 10; |
运行结果: