Day1
要点1:写在形参上的数组,编译器只会看成是指针,而不会看成是数组
例如:
Func(int a[])//形参写在函数体内和写在括号内是一样的,只不过是具有对外的属性而已。
Func()
{
Int a[];
}
{
sizeof(a);//此值为4,而不是数组的大小,他是指针这种数据类型的大小
为什么会当成指针处理?
因为传递指针的效率比直接传值的效率高很多,这也真的c语言的优势所在。
}
站在编译器的角度思考问题
数据类型和内存的关系?
C语言为什么会引入数据类型?
数据类型就是固定内存块大小的别名。
Int a //告诉c编译器分配4个字节的内存
Int a[10]
a 和&a是不一样的,a是代表的数组第一个元素的地址,&a是整个数组的首地址,他们的值是一样的,但是a+1和&a+1的值是不一样的,a+1是代表的数组的第二个元素,&a+1向后增加了40个字节。
数据类型的封装
Void *可以存储任何类型的地址
malloc()函数返回的是void指针类型
需要类型转换。也就是说void指针类型赋值给其他类型的指针时要强制类型转换。
P1= NULL;
Int P2=2;
P1=&p2;//void指针类型可以直接接受任何指针
数据类型的封装很重要。
变量的本质
是一段内存空间的别名,就是门牌号
变量是代码,存在代码区。
向变量写数据,是向变量所指向的内存空间写数据,不是向变量写数据。
修改变量的值有两种方法
1直接修改值
2通过地址间接的修改值 *(int *)1245245=1
变量的三要素:名称、大小、作用域。
变量的生命周期
内存四区模型
函数调用模型
内存四区
栈区、堆区、全局区、代码区
数组申请的空间在栈区
理解指针的关键是在内存
要清楚的知道内存空间来自栈区还是堆区
栈区的开口方向 在debug情况下,开口向下
在resease情况下,开口向上
在数组buf中,不管是开口向上还是向下,buf+1永远是向上的
不断的给指针赋值,就是不断的改变指针的指向
free(a)执行完之后还需要将a=NULL避免野指针
字面量
Int a = 0;其中0就是字面量,没有放在栈区也没有放在堆区,他和代码一样放在代码区
指针
间接赋值是指针存在的最大意义
一级指针的技术推演
在调用函数时,是传值传递,是将实参复制给形参,如果要间接改变一个值,需要将其的上级指针作为实参进行传递。
一级指针到二级指针的技术推演
通过二级指针间接修改一级指针的值
一级指针间接修改值的三个条件:定义两个变量、建立关联、通过*间接修改
用一级指针去修改零级指针的值
用二级指针去修改一级指针的值
用N级指针去修改N-1级指针的值
指针做函数参数是我们研究的重点,指针是子弹,函数是枪管,只有两者结合起来才能发挥威力
掌握了指针只是掌握了C语言的半壁江山,还有半壁江山是函数指针,也就是回调函数
指针做函数参数,有输入和输出特性,输入是在主调函数中分配内存,输出是在被调函数中分配内存
被调函数在栈区分配的内存不能给主调函数使用,因为被调函数一旦执行完,就是被系统析构
没有内存,哪来的指针!
二级指针做函数形参,一般是在被调函数中分配内存,然后返回给主调函数中使用
一级指针做输入,一般情况下是一维数组做参数,字符串
在c语言中,没有字符串这种数据类型,通过字符数组来模拟字符串
字符串是以0结尾的
字符串的内存分配,可以在栈区、堆区和全局区
char a[]=”abc”;作为字符数组,有4个字节,作为字符串有3个字节
strlen()字符长度,不包括\0
sizeof()内存大小,包括\0
数组名是常量指针,不可以修改,析构内存的时候,保证这块内存空间能安全释放
在函数中经常用一个辅助指针变量去接形参指针,作为缓存。不要随便的改变形参的值
Strstr()和while模型,计算子串在原串中出现的次数
判断指针变量而不是判断指针所指向的内存空间
*Count++和(*count)++是不一样的,++的优先级高于*,但是++是后缀表达式,先要执行*然后再对地址++,一定要注意了!
Const的用法一定要会用啊,兄弟!
指针的输入输出模型
在被调函数中分配内存为输出模型
在主调函数中分配内存为输入模型
二级指针:指针数组、二级数组和malloc内存
二级数组的步长与其他两个不一样
多级指针 要避免野指针