指针是C语言的灵魂!!!
- CPU的三大总线
地址总线、数据总线、控制总线
RAM,ROM和外设寄存器,都有特定而独立的地址空间。
CPU能寻址的总空间取决于CPU的地址总线的位数。
C语言中的指针就是有类型的地址!!!
地址就是地址总线上的地址码。
而类型则决定了我们要从这个地址码上读写数据的长度!!!
- 指针常量
{
char *p;
char str[] = "1234567890";
for(p = str;*p != '\0';p++)
{
printf("%c ",*p);
}
printf("\r\n");
}
// 下面的代码编译不能通过,str 是常量指针不能被修改。
{
char str[] = "1234567890";
for(;*str != '\0';str++)
{
printf("%c ",*str);
}
printf("\r\n");
}
字符串指针和函数的首地址、结构体首地址都是常量。在编译的时候就确定了。所以我们要额外定义一个指针变量指向他们,指针变量是可以改变的。
- 数组和指针
[]其实并不是什么数组下标,它真正的名字叫**“指针运算符”**
不要把[n]看成是数组的专利,他是很灵活的![n]的正真意义:
以[]前面的指针(有类型的地址)为基准,找到它后面n个类型长度的地址位置,取出这个位置上的数据。
- 数组指针 和 指针数组
数组指针,首先它是指针,p与*先结合,再确定是一个数组
*p //第一步:定义一个指针
uint32_t(*p)[5] //第二步:指向一个特定类型的指针
指针数组,首先他是数组,p与[]先结合,再确定是一个指针数组
p[5]//第一步:定义一个数组
uint32_t*(p[5])// 第二步:确认这个数组存放的数据类型
函数指针,首先他是指针,p与*先结合,再确定它是个函数指针
*p //第一步:定义一个指针
void(*p)(int,int) //第二步:指向一个特定类型的指针
//函数指针定义的另一个思路
int fun (int a,int b) //第一步:写出函数原型
int(*fun_p)(int,int) //第二步:将函数名替换成指针名
//定义函数指针时一般用tepedef
tepdef int(*)(int,int) fun_p;
- 多维数组和指向它的指针
//定义一个指向二维数组的指针
uint32_t array[2][3] //二维数组
(*(*p)) // 第一步:二维指针
uint32_t(*(*p))[2][3]// 第二步:指向特定类型的二维数组指针
- 动态分配内存malloc
不要滥用动态分配,动态分配是有代价的!!!
1、代码里尽量不用动态分配,尽量使用静态分配。将内存在编译期间就定下来。
2、使用了malloc一定记得对其所申请的内存进行free。
3、调用malloc之后,一定要对其返回值进行判断,而不能贸然去使用。因为他可能返回NULL。
4、不要频繁调用malloc,因为malloc会产生内存的碎片(单向链表管理数据)。
5、适当设置heap size,也就是堆的大小。
未完待续