我们看到pa的类型是
int*
,我们该如何理解指针的类型呢
这⾥pa左边写的是
int*
,
*
是在说明pa是指针变量,⽽前⾯的
int
是在说明pa指向的是整型(int)
类型的对象。
![](https://img-blog.csdnimg.cn/direct/2738f3c6d2ab412f944886054df92c88.png)
解引⽤操作符
我们将地址保存起来,未来是要使⽤的,那怎么使⽤呢?
在现实⽣活中,我们使⽤地址要找到⼀个房间,在房间⾥可以拿去或者存放物品。
C语⾔中其实也是⼀样的,我们只要拿到了地址(指针),就可以通过地址(指针)找到地址(指针)
指向的对象,这⾥必须学习⼀个操作符叫解引⽤操作符(*)。
上⾯代码中第7⾏就使⽤了解引⽤操作符,
*pa
的意思就是通过pa中存放的地址,找到指向的空间,
*pa其实就是a变量了;所以*pa = 0,这个操作符是把a改成了0.
有同学肯定在想,这⾥如果⽬的就是把a改成0的话,写成
a = 0;
不就完了,为啥⾮要使⽤指针呢?
其实这⾥是把a的修改交给了pa来操作,这样对a的修改,就多了⼀种的途径,写代码就会更加灵活,
后期慢慢就能理解了。
指针类型变量的意义
指针解引用
![](https://img-blog.csdnimg.cn/direct/e168880728e542f0b5a7a9362d715167.png)
![](https://img-blog.csdnimg.cn/direct/5dbb13e2426c460cb03c873ab128e250.png)
任务:上面两段代码,调试观察内存的变化,对比发现了什么?
发现:第一段代码会将n的4个字节全部改为0;但是第二段代码只是将n的第一个字节改为0。
结论:指针类型决定了对指针解引用的时候有多大权限(一次可以操作几个字节)。
比如:char*的指针解引用只能访问一个字节,而int*的指针解引用就可以访问4个字节。
指针++(--)跳过多少字节
![](https://img-blog.csdnimg.cn/direct/9d998c24144f4578894dba64c55e1431.png)
由此可见char*指针加一跳过一个字节,int*指针加一跳过4个字节; 结论:指针类型决定了指针向前或者向后走一步有多大(距离)。
void* 指针
void* 类型,无具体类型的指针(泛型指针),void* 类型的指针大部分使用在函数参数的部分,用来接收不同类型数据的地址。
但是void* 类型的指针不能直接进行指针的+-整数和解引用运算。
字符指针与数组指针
在指针的类型中我们知道有⼀种指针类型为字符指针
char*
代码
const char* pstr = "hello bit.";
特别容易让同学以为是把字符串
hello bit
放
到字符指针
pstr
⾥了,但是本质是把字符串
hello bit.
⾸字符的地址放到了pstr中。
const修饰指针
在C语言中,const是constant的缩写,翻译是“恒定不变的”。它是定义只读变量的关键字。或者说const是定义常变量的关键字
const修饰的变量被称为常变量,具有常属性,但是本质上还是变量。
保护被修饰的东西,防止被意外修改,增强程序的健壮性。
提高程序的运行效率。编译器通常不为普通const常量分配存储空间,而是将他们保护在符号表中,使得它成为一个编译期间的常量,没有存储和读取内存的操作,使得它的运行效率也很高。
const int* p (int const *p)和int *const p的区别
![](https://img-blog.csdnimg.cn/direct/733f909feaf54bdebf93bc1be860488c.png)
![](https://img-blog.csdnimg.cn/direct/44026b1e2ce24c158d067d0129344c8f.png)
总结:
①const int* p (int const *p):const放在*的左边。修饰的是*p,*p(指针指向的内容)不能修改;p(指针变量本身)可以修改
②int * const p :const放在*的右边。修饰的是p,p(指针变量本身)不可以修改;*p(指针指向的内容)可以修改。
③int const * const p (const int * const p):*的左右两边都有const,修饰的是*p和p,所以*p和p都不能被修改。
指针运算
指针 +- 整数
数组在内存中是连续存放的,只要知道第一个元素的地址,顺藤摸瓜就可以找到后面所有元素。
![](https://img-blog.csdnimg.cn/direct/27f1983fc856434daf2ad4b952ce2123.png)
指针与数组
什么是指针数组
之前我们学习了指针数组,是⼀种数组,数组中存放的是地址(指针)。
数组指针变量是指针变量?还是数组?
答案是:指针变量。
我们已经熟悉:
•
整形指针变量:
int * pint;
存放的是整形变量的地址,能够指向整形数据的指针。
•
浮点型指针变量:
float * pf;
存放浮点型变量的地址,能够指向浮点型数据的指针。
那数组指针变量应该是:存放的应该是数组的地址,能够指向数组的指针变量。
int
(*p)[
10
];
解释:p先和*结合,说明p是⼀个指针变量,然后指针指向的是⼀个⼤⼩为10个整型的数组。所以p是 ⼀个指针,指向⼀个数组,叫 数组指针。
这⾥要注意:[]的优先级要⾼于*号的,所以必须加上()来保证p先和*结合。
⼆维数组传参的本质
本质穿的是地址;
这⾥实参是⼆维数组,形参也写成⼆维数组的形式,那还有什么其他的写法吗?
⾸先我们再次理解⼀下⼆维数组,⼆维数组其实可以看做是每个元素是⼀维数组的数组,也就是⼆维
数组的每个元素是⼀个⼀维数组。那么⼆维数组的⾸元素就是第⼀⾏,是个⼀维数组。
如下图:
![](https://img-blog.csdnimg.cn/direct/16e96ff61a26469bb6ada987d1fbabf8.png)
![](https://img-blog.csdnimg.cn/direct/ed58105c10684cd58a60240b78b3ceb9.png)
所以,根据数组名是数组⾸元素的地址这个规则,⼆维数组的数组名表⽰的就是第⼀⾏的地址,是⼀
维数组的地址。根据上⾯的例⼦,第⼀⾏的⼀维数组的类型就是
int [5]
,所以第⼀⾏的地址的类
型就是数组指针类型
int(*)[5]
。那就意味着⼆维数组传参本质上也是传递了地址,传递的是第⼀
⾏这个⼀维数组的地址,那么形参也是可以写成指针形式的。如下:
1
#
include
<stdio.h>
2
3
void
test
(
int
(*p)[
5
],
int
r,
int
c)
4
{
5
int
i =
0
;
6
int
j =
0
;
7
for
(i=
0
; i<r; i++)
8
{
9
for
(j=
0
; j<c; j++)
10
{
11
printf
(
"%d "
, *(*(p+i)+j));
12
}
13
printf
(
"\n"
);
14
}
15
}
16
17
int
main
()
18
{
19
int
arr[
3
][
5
] = {{
1
,
2
,
3
,
4
,
5
}, {
2
,
3
,
4
,
5
,
6
},{
3
,
4
,
5
,
6
,
7
}};
20
test(arr,
3
,
5
);
21
return
0
;
22
}
总结:⼆维数组传参,形参的部分可以写成数组,也可以写成指针形式。
sizeof 与strlen对比
sizeof
在学习操作符的时候,我们学习了
sizeof
,
sizeof
计算变量所占内存内存空间⼤⼩的,单位是
字节,如果操作数是类型的话,计算的是使⽤类型创建的变量所占内存空间的⼤⼩。
sizeof
只关注占⽤内存空间的⼤⼩,不在乎内存中存放什么数据。
⽐如:
1
#inculde
<stdio.h>
2
int
main
()
3
{
4
int
a =
10
;
5
printf
(
"%d\n"
,
sizeof
(a));
6
printf
(
"%d\n"
,
sizeof
a);
7
printf
(
"%d\n"
,
sizeof
(
int
));
8
9
return
0
;
10
}
strlen
strlen 是C语⾔库函数,功能是求字符串⻓度。函数原型如下:
1
size_t
strlen
(
const char
* str );
统计的是从
strlen
函数的参数
str
中这个地址开始向后,
\0
之前字符串中字符的个数。
strlen
函数会⼀直向后找
\0
字符,直到找到为⽌,所以可能存在越界查找。
#
include
<stdio.h>
int
main
()
{
char
arr1[
3
] = {
'a'
,
'b'
,
'c'
};
char
arr2[] =
"abc"
;
printf
(
"%d\n"
,
strlen
(arr1));
printf
(
"%d\n"
,
strlen
(arr2));
printf
(
"%d\n"
,
sizeof
(arr1));
printf
(
"%d\n"
,
sizeof
(arr2));
return
0
;
}
这样可以解释为啥这里n=1;
sizeof 和 strlen的对⽐
数组和指针笔试题解析
⼀维数组
int
a[] = {
1
,
2
,
3
,
4
};
printf
(
"%d\n"
,
sizeof
(a));
printf
(
"%d\n"
,
sizeof
(a+
0
));
printf
(
"%d\n"
,
sizeof
(*a));
printf
(
"%d\n"
,
sizeof
(a+
1
));
printf
(
"%d\n"
,
sizeof
(a[
1
]));
printf
(
"%d\n"
,
sizeof
(&a));
printf
(
"%d\n"
,
sizeof
(*&a));
printf
(
"%d\n"
,
sizeof
(&a+
1
));
printf
(
"%d\n"
,
sizeof
(&a[
0
]));
printf
(
"%d\n"
,
sizeof
(&a[
0
]+
1
));
字符数组
![](https://img-blog.csdnimg.cn/direct/21c8b5cc654d43f4b60809f93e479f21.png)
![](https://img-blog.csdnimg.cn/direct/7320ba78c49e410d8a0966ad9a0093c6.png)