C语言几个重要知识点

C语言几个重要知识点

1、函数

上一篇博文讲了c语言入门,里面有涉及主函数,这里给大家再深入讲一下函数这个概念。

我在本篇博文里将函数比喻为一种工具或者服务,我们要计算一个方程式或者记录一些日志或者进行一些什么业务功能的时候,就可以设计一个函数来实现。如果一个函数不够也可以设计多个函数。

栈空间

函数里定义的数组或结构体变量皆使用的是栈空间,而操作系统给栈空间分配的大小是固定且有限的,一般不大。在调度函数的过程中可能出现嵌套调度的情况,如果调度层次过深可能会导致栈溢出,在程序设计时应该要考虑这一点。第二个要考虑的地方是函数入参的设计,如果buff指针和基本类型指针在一起有可能出现段错误甚至出参被意外修改的情况。

递归函数

有一种函数可以自己调度自己来实现业务功能,当然递归次数不能太多否则会出现栈空间溢出的情况,例如最为著名的汉诺塔问题,使用递归函数的设计思路是非常容易理解的,如果不用递归求解就会很难,因为以面向过程的思想去设计需要从开始到结束详细推演每一步移动过程。而用递归思想只需要设计一个可以自己调度自己的函数,并且存在结束退出的条件即可,我认为这是一种非常有意思且值得学习的设计思路。下面以阶乘为例介绍这个递归思路:

#include <stdio.h>
 
double factorial(unsigned int i)
{
   if(i <= 1)
   {
      return 1;
   }
   return i * factorial(i - 1);
}
int  main()
{
    int i = 15;
    printf("%d 的阶乘为 %f\n", i, factorial(i));
    return 0;
}

首先,阶乘在数学上定义5的阶乘就是5!= 5X4X3X2X1;如何用c程序来求解N!呢,我们发现阶乘的定义N!与(N-1)!是有明确关系的,当然N==1就是最小值,负数和0的阶乘不考虑都返1,如果N>1时就可以用N!= N*((N-1)!)于是就有了上面的程序代码。总结来说就是N与N-1的明确关系以及N<1的退出条件就构成了这个递归阶乘函数。

动态库和静态库

在linux平台动态库的后缀为so,静态库的后缀为a,在windows平台上动态库的后缀为dll,静态库的后缀为lib。
动态库和静态库的定义可以参见这篇博文:

https://blog.csdn.net/Burt3/article/details/119345903
C语言中的静态库与动态库

这里我想补充说明的是在对外提供业务API时,往往用的是动态库而非静态库,因为动态库可以方便我们更换版本后不会影响到调度我们的上层应用,否则需要重新编译。

2、数据类型和数据结构

C语言里有固定的几种数据类型:

类型定义
char/unsigend char占1字节空间,char字符在ASCII表里可查,最高位为0;unsigned char* 可表示一段字节流,可用于各个功能模块之间传递buff时使用
int占4字节空间,一般用于私有协议表示长度字段
short占2字节空间,一般用于私有协议表示长度字段
long占4字节空间,一般用于大数运算

除了常见的固定类型外,还可以通过struct 关键字创建自定义的数据类型,很多复杂问题就是通过自定义的数据类型来解决的,经典的有链表(单向链表、双向链表、hash链表等)、树(二叉树、平衡树、红黑树)、队列、图、堆等。

3、循环

c语言包括for循环、while循环、do while循环;而循环是数学运算、字符串处理、业务算法等问题的求解基石,比如最短路径求解需要循环、树结构的先序遍历需要循环、单片机里的主控程序需要循环、服务器提供业务的服务程序也需要循环。循环语法虽然简单,但它却是解决许多疑难问题必须要用到的知识点。

4、数组

数组本质上是按顺序存储一系列相同类型的数据,我们可以通过下标非常快速的取得数组里的元素,因为首地址取偏移是一个指令级别的动作所以非常快。
数组的定义是非常容易理解的,很多依靠指针解决的问题,依靠数组也可以解决,一般不是特别难解决的问题建议都用数组解决,就比如队列结构类型就可以用数组来实现,但是前提是必须预先分配空间。
指针区别于数组的优势就在于它不需要提前分配而是按需分配不会存在内存浪费的问题,同时如果所需空间过大数组就不合适了,需要用指针申请堆空间来解决。
多维数组,可以理解为多维空间。以一维数组为例,数组元素就相当于一条线上的不同点;同理以二维数组为例,数组元素也就相当于平面上的点。

5、结构体

C语言里的结构体和面向对象设计语言里的类有点像,它本质上就是为了方便表达和描述研究的个体。当需要处理批量数据时,如果能够抽象出共同点并组合成一个结构体就会很方便求解问题。比如统计班级期末考试语文成绩不及格的学生有多少个,就可以将数据抽象为以学生为个体,期末成绩为成员变量的结构体。当然在网络通信协议里的帧头格式也可以抽象为结构体方便统计和处理数据报文交互情况。

6、指针

C语言里区别高手和低手水平的一个知识点就是指针了,指针的灵活妙用可以参见linux内核源码,这个不再深入讨论。
我们对指针先来一个定义,在C语言的世界里指针本质上就是地址,如何获取地址里的内容、该内容有多长的空间需要得到该指针的类型,如果指向的是一个字符,那就是1个字节,如果指向的是一个short,那就是两个字节,如果指向的是一个自定义的结构体那就是sizeof(结构体),如果指向的是buff,那长度必须提前指明。
这里举几个关于指针的例子:

回调函数

#include<stdio.h>
void test1()
{
	printf("hehe\n");
}
void test2(void (*p)())
{
	(*p)();
}
int main()
{
	test2(test1);
	return 0;
}


回调函数是指在不清楚被调函数定义的情况下调度该函数,通过指针函数的方式实现,有一个场景大家比较容易理解,玩单片机的朋友知道定时器函数,该函数就是在超时后调度,它并不需要知道超时后做什么,只需要知道函数名即可设计超时功能,并不会影响到上层业务逻辑;还有一种场景是网络协议交互时,发送报文给对方后可以设计回调处理对方回执报文同时也不影响对方发起的业务报文处理,因为新增的回调函数只处理回执情况。

句柄

句柄是void* 指针,它可以隐藏数据类型,比如密钥句柄,在安全要求高的场景下密钥是不能出设备的,但是运算时需要怎么办,就可以通过返句柄的方式实现,又比如设备句柄,在操作系统层面如何为应用层提供访问设备的能力呢,就可以通过返设备句柄来实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

体制码农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值