只要你愿意 开始总比放弃好。 Roman.
愿我们都有自己的目标并正在为其不懈努力。
-----------------------------------------------------------------------
0. 补充:
寄存器(读取较快):ebp 、 esp (前两个存放的是地址) 、eax 、ebx 、ecx 、edx
****************************************
一、指针是什么
一)指针理解的两个要点
1. 指针是内存中一个最小单元的编号,也就是地址
2. 平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量
二)补充
1. 内存中最小单元是一字节
2.
- 32位虚拟空间:
CPU生成32位地址(即:32bit == 4byte)-- 通过地址线传输 -- 定位到内存空间
- 64位虚拟空间:
CPU生成64位地址(即:64bit == 8byte)-- 通过地址线传输 -- 定位到内存空间
- 注:每根地址线在寻址的时候产生高电平(高电压)和低电平(低电压),即 1 或者 0
- 每个地址(32 or 64 根地址线组成一个地址)标识一个字节,共有 (2^32 or 2^64)个地址
三)指针变量
1. 我们可以通过 &(取地址操作符)取出变量的内存起始地址,把地址存放到一个变量中去,这个变量就是指针变量
2. 总结:指针变量,用来存放地址的变量。(存放在指针中的值都被当做地址来处理)
四)小结
1. 指针就是地址,口语中的指针一般就是指指针变量
2. 指针是用来存放地址的,地址是唯一标识一块地址空间的
3. 指针大小:在32位平台上--4字节 64位平台上--8字节
****************************************
二、指针和指针类型
1. 指针类型 决定了 指针在被解引用的时候访问的权限。(即:操作的大小)
如:① 整型指针解引用访问 4字节
②字符型指针解引用访问 1字节
2. 指针类型决定了指针向前 or 向后 走一步走多大距离
如:① int* + n --> 跳过 n * sizeof (int) == n *4 个字节
② char * + n --> 跳过 n * sizeof (char) == n *1 个字节
3. 补充1: sizeof(long) >= sizeof(int)
32 位环境下: sizeof(long) == 4 byte
64 位环境下: sizeof(long) == 8 byte
4. 注: sizeof(float) == 4 字节
5. 补充:
- 不管是二维数组还是一维数组,在传参的时候都不会去创建数组
- 一维数组传参的时候,形参的数组大小可以省略
- 二维数组传参的时候,形参的数组中,行可以省略,列不可以省略
- 在声明时,二维数组如果要省略行,则一定要进行初始化
- 整型和浮点型数据,在内存中存储方式不同
如:
float n = 3.14f ;
int * p = &n;
*p ; // ???未知
****************************************
三、野指针
野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
一)野指针的成因
1. 指针变量未初始化
1)补充:局部变量未初始化则自动初始化为随机值
2)如何规避:
- 如果已知变量,则取地址
- 若未知,则赋值 NULL(本质是0),0是坚决不允许被访问的,所以访问指针是有条件的:指针变量不等于NULL
3)注:为什么0不能被访问?
内存中有些空间是不能被用户访问的,只是供操作系统(内核)访问,该空间包括0
2. 指针越界访问
#include <stdio.h>
int main()
{
int arr[10] = {0};
int *p = arr;
int i = 0;
for(i=0; i<=11; i++) // i的范围实际应该为: 0-9
{
//当指针指向的范围超出数组arr的范围时,p就是野指针
*(p++) = i;
}
3. 指针指向的空间释放
如:
int* test()
{
int a = 10;
printf("%d\n",a);
return &a;
}
int main()
{
int* p = test();
*p = 100;
return 0;
}
注:局部变量出了函数后被销毁,空间释放,找不到该地址指向的变量进行赋值操作
二)如何规避野指针
1. 指针初始化
2. 小心指针越界
3. 指针指向的空间释放,及时置 NULL :不想使用时也置NULL
4. 避免返回局部变量的地址
5. 指针使用之前检查有效应:即-判断指针变量不等于NULL
****************************************
四、指针运算
1. 补充:随数组下标增大,地址由低到高变化
2. 指针运算是指: 指针可以进行大小比较
3. 指针 + - 整数: 如 *vp++; // +1则跳过一个元素
4. 指针 - 指针
1)前提:两个指针必须指向同一块空间,即同一个数组
2)结果:(指针 - 指针)的绝对值 得到的是指针和指针之间元素的个数
(指针 - 指针 有正有负)
5. 实例:my_strlen() -- 求数组长度(元素个数)
// 注:三种方法:计数器、递归、指针-指针
// 指针 - 指针 : 只适用于字符数组
//my_strlen() -- 求数组长度(元素个数)
//指针-指针
#include<stdio.h>
int my_strlen(char* arr)
{
char* start = arr; //首元素地址
while (*arr)//寻找\0--末尾
{
arr++; //跳过一个元素
}
return arr - start;
}
int main()
{
char arr[] = "abcdefghi";
int len = my_strlen(arr);
printf("长度:%d\n", len);
return 0;
}
6. 指针的关系运算
1)即:比较指针之间的大小
2) 实例
for ( vp = & values [ N_VALUES ]; vp > & values [ 0 ];){*-- vp = 0 ; // 先减减,再使用(赋值)}代码简化 , 这将代码修改如下:for ( vp = & values [ N_VALUES - 1 ]; vp >= & values [ 0 ]; vp -- ){* vp = 0 ;}//实际在绝大部分的编译器上是可以顺利完成任务的,然而我们还是应该避免这样写,因为标准并不保证它可行。
- 标准规定:
****************************************
五、指针和数组
1. 数组可以通过指针来访问
2. 数组名是首元素地址,但是有两个例外:
- sizeof(数组名),数组名表示整个数组,计算的是整个数组的大小
- &数组名,数组名表示整个数组,取出的是整个数组的地址
+1 表示跳过整个数组, 如:&数组名+1
- 补充:
① 数组可以通过指针来访问,前提是:数组是连续存放的,是同一块空间
②数组和指针不是同一回事儿:
数组是一块连续的空间, 指针是存放地址的变量
可以通过指针访问数组
****************************************
六、二级指针
1. 二级指针是 指针的指针
2. 举例:
//二级指针
#include<stdio.h>
int main()
{
int a = 0;
int* pa = &a;
int** ppa = &pa;
return 0;
}
// int * pa : *表示pa是指针变量, int 说明 pa 指向的是 int类型的数据
// int* * ppa : *(ppa之前最接近ppa的*)表示ppa是指针变量, int* 说明 ppa指向的对象是 int* 类型的数据
// *ppa == pa ;
// *pa == a;
// **ppa == a;
****************************************
七、指针数组
指针数组 是存放【指针类型】的数组
1. 如: int* arr[5]; //指针数组,元素类型是 int*
2. 模拟二维数组:指针模拟
//模拟二维数组:指针模拟
#include<stdio.h>
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 2,3,4,5,6 };
int arr3[] = { 3,4,5,6,7 };
//元素类型相同
int** num[] = { &arr1,&arr2,&arr3 };//数组名即首元素地址,地址即指针
// 二级指针是地址的地址
int size1 = sizeof(arr1) / sizeof(arr1[0]);
int size2 = sizeof(num) / sizeof(num[0]);
int i = 0;
for (i = 0; i < size2; i++) //决定行(把每个一维数组都看作一行)
{
int j = 0;
for (j = 0; j < size1; j++) //决定列(每个一维数组中元素个数即列)
{
//printf("%d ", num[i][j]); //方式一
printf("%d ", *(num[i]+j)); //方式二
//num[i]找到行--即第i个一维数组首元素地址,加j--即第i行跳过j个元素,解引用后即得元素
}
printf("\n");
}
return 0;
}
------------------------一个人所有的愤怒都来源于对自己无能的痛苦。------------------------