史上最全最详细最好的精品C语言万字长文(下)---看完直接手撕所有八股面试考研期末

函数

在函数定义处,对形参的改变不影响实参,形参是实参的临时拷贝

返回值类型 函数名(形参列表){ 语句代码块 }

函数←面向过程

良好的习惯:在语句前缩进使用4个空格,不要用Tab键

良好的习惯:在if或for代码块结束的 } 后面加注释,注明结束

良好的习惯:如果一行表达式中的运算符较多,多使用括号来区分各运算符的优先级,达到不了解运算优先级也能一目了然的效果

良好的习惯:不要写太过复杂的表达式,尽量拆分

良好的习惯:在传参时,如果传的是指针,而指针在函数中又不会发生修改,只是单纯的输入,在形参列表指针前面+const

函数都是会被调用的,main函数也不例外,main函数是被mainCRTStartup函数调用,再往上就是操作系统范畴,因为程序执行都是要被加载到内存的,所以后续需要操作系统来管理

函数调用就会形成栈帧

栈区是向下增长的,即向低地址扩大

eip保存的是要执行的下一条指令的地址

临时拷贝的形成是在函数调用之前,实参的临时拷贝是要压入栈的,栈顶指针esp,向上(低地址)扩大。变量的入栈顺序是形参列表从右向左

在函数调用之前,先将形参实例化,形参的临时拷贝要入栈,找到实参变量的地址,将实参变量的内容存在寄存器eax,ecx,然后将eax,ecx压入栈顶,esp上移。然后保存函数调用后的返回地址,即函数调用call汇编语句的下一句汇编语句的地址,压入栈,esp上移。开始执行函数,eip保存的地址变为函数起始地址,然后在函数内部依次向下执行,执行结束后返回之前保存的地址。

内存管理

exit :程序退出的函数 在头文件stdlib中

perror :说明错误原因。显示与上一个系统调用相关联的错误描述。它通常被用于处理和显示来自errno变量的错误信息。使用例子:perror( 字符串 )

使用perror时,需要提供一个字符串参数s,该参数所指的字符串会先打印出,后面再加上错误原因字符串。此错误原因依照全局变量errno的值来决定要输出的字符串。举例:fopen函数调用失败,并设置errno为错误码。然后,可以使用perror函数来打印与该错误码相关的描述性错误消息。

因为栈区空间是非常有限的,栈区空间内的栈帧出了作用域就销毁了,如果在栈区开辟的空间太大,也就是创建的栈帧太多,就会导致栈溢出(stack overflow)。所以需要在堆区开辟空间才能满足大空间的开辟,在堆区上开辟的空间,在使用结束时,需要及时free(p),p是这块空间的最低地址。堆区才能对用多少空间开多少空间而不浪费实现一个精准的管理,栈区不行

对开辟的空间进行初始化,如下图

一直向系统申请内存而从不释放,就会发生内存泄漏

程序退出之后,内存泄漏问题就会自动解决,像服务器后端程序这些常驻程序(加载进内存中永不退出)才会因为内存泄漏造成巨大影响。

free的本质是将堆空间和指针指向解除对应关系

内存管理的本质是空间时候申请,申请多少,空间什么时候释放,释放多少

可变参数列表

可变参数列表必须有一个确定参数,因为在栈帧结构中,实参的临时拷贝是连续存放的,知道一个临时变量的地址,就可以访问到所有的形参

va_list 是一个char*类型的指针,通过这个地址能找到其他的临时变量。让这个指针指向最后一个元素的确定地址

va_start 通过指针操作,按照类型,从可变部分,依次取参数。强转成char*,然后根据类型大小,考虑4字节对齐,向下依次读取参数

va_arg 把当前元素提取出来,arg指向下一个待访问元素

va_end 将指针置为空,避免野指针

实际传入的参数如果是char short float 编译器在编译的时候,会自动进行提升

所以printf中,必须有%d等,进行格式控制,%确定类型,有几个%就有几个参数,以此来确定参数个数和类型

原理:

1.可变参数列表的函数,也是函数调用,也要形成栈帧

2.栈帧形成前,临时变量从右向左入栈,各临时变量在内存空间是连续存放的

3.短整型在可变参数部分,会进行整型提升,因此在函数内部提取该数据的值时,要考虑提升之后的值

命令行参数

argument参数

main函数有3个参数:

1.int argc 命令行参数个数

2 . char* argv[] 指针数组,里面的指针分别指向每一个命令行字符串,这些字符串彼此用空格隔开,组成命令行参数

3.char* env[] 也是一个指针数组,里面的指针指向很多个字符串(环境变量)

命令行参数的作用,可以在main函数中,让不同的选项代表不同的意义。分别对带有各种选项的情况进行判断,如果符号就执行相对应的代码,表现出不同的功能

递归

递归本质上也是函数调用,形成和释放栈帧,时间+空间。由于资源有限,所以递归不能无限制递归下去。核心思想:大事化小+递归出口 目标问题的子问题也可以使用相同的方法解决

特点:效率一般,代码简单

迭代:效率较高,代码复杂

扩容

malloc和realloc

realloc分为原地扩容和异地扩容,原地扩容就是扩容的地址在原来的地址,异地扩容就是扩容的地址和原来的地址不一样 ,就是在堆区的另外一块地方重新找的一个更大的地方,然后将数据拷贝过去

pow

幂次方pow(10,2)  10的平方

柔性数组

表面上数组大小是0,实际是能编译通过的。只能在结构体的最后一个字段使用

本质上就是结构体的空间的后面的第一个元素的地址,在之后的malloc时,选择大小,就可以在结构体中形成变长数组

结构体的地址和结构体的第一个元素的地址在数值上是一样的

  • 18
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值