指针初步学习
指针初步学习
1.指针是什么?
电脑内存这么大我们怎么管理? 于是我们创造了指针。 - 指针是内存最小单位的一个地址
假设以下一格为一个字节(Byte) 类比为房间,如何才能找到每个房间,于是就进行编号。
| 编号 | 内存单元 |
|---|---|
| 1 | |
| 2 | |
| 3 | |
| ... | ... |
这个编号为内存地址,即为指针。
假设我们要对int a取地址,int大小为4个字节,C语言就会取出第一个字节的地址。
如: | 编号(本质为二进制但是用16进制展示)|内存单元 | |--:|:---:| |0x00dbfd98|a| |0x00dbfd99|a| |0x00dbfd9a|a| |0x00dbfd9b|a|
此处&a = 0x00dbfd98。
但是注意:我们在口头中所说指针一般为C语言的指针变量。
1
2
3
4int a = 10;
int* pa = &a;
//一般我们在这里就把pa这个指针变量说成指针
//本文中我会区分指针与指针变量。
在不同的机器上,指针长度不同,32位即32bit,能管理4GB的内存(二进制:11111111 11111111 11111111 11111111),所以在32位机器上一个指针变量大小为4字节。
2.指针和指针类型
1 | |
这些不同类型的指针变量在32位下都是4个字节, 那么为什么要区分这些不同类型的指针呢?
2.1指针类型的意义
举例1: 1
2
3int a = 0x11223344;
char* pc = (char*)&a;
*pc = 0;
所以指针类型决定了指针在被解引用时访问几个字节,如果是char*在解引用是访问1个字节,导致了例子中的情况。
举例2: 1
2
3
4
5
6
7int a = 0x11223344;
char* pc = (char*)&a;
int* pi = &a;
pc+1;//这里加1会给地址加1个字节
pi+1;//这里加1会给地址加4个字节
那么int*与float*可以通用吗?
显然不可以,在解引用时对于内存的操作仍是不同的。
3.野指针
3.1什么是野指针?
定义:指针指向的位置是不可知的。
举例: 1
2int* p ;
*p = 10;
此外还有:
- 指针越界访问(如访问超出数组长度的地址) -
指针指向的空间释放(如函数返回一个指针后被销毁)
3.2如何避免野指针的出现。
- 对指针明确初始化(或初始化为
NULL,但此时无法解引用)。1
2
3
4
5
6//以下为一种安全的初始化方式:
int* p = NULL;
if (p3 != NULL)
{
*p3 = 100;
} - 避免越界
- 避免局部变量的指针
- 使用前检查指针的有效性
4.指针运算
4.1指针+-整数
举例: 1
2
3
4
5
6
7#define N_VALUES 5
float values[N_VALUES];
float *vp;
for(vp = &values[0]; vp < &values[N_VALUES];)
{
*vp++;
}*vp++拆分为*vp;和vp++;
4.2指针-指针
1 | |
指针减去指针得到的是指针之间元素的个数。但不是所有的指针都能相减,只有指向同一块空间的指针才能相减,才有意义。
4.2.1用法
举例: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17int my_strlen(char* str)
{
char* start = str;
while (*str != '\0')
{
str++;
}
return (str - start);
}
int main()
{
int len = my_strlen("abcdef");
printf("%d\n",len);
return 0;
}
但是有没有指针+指针呢? 有,但是无意义。类比于生活中的日期加日期,无意义。
4.3指针的关系运算
- 其实就是比较大小
举例: 1
2
3
4
5
6
7#define N_VALUES 5
float values[N_VALUES];
float *vp;
for(vp = &values[N_VALUES-1]; vp >= &values[0];vp--)
{
*vp = 0;
}N_VALUES-1访问了数组前的内存是不推荐的(但是可以访问数组后,即数组越界只允许往后越界)。
5.指针与数组
- 数组是一组相同类型元素的集合
- 指针变量是一个变量,存放的是地址
1 | |