分享

知识盘点:老师上课不会讲到的C语言知识!补了课的已经面试成功

 新用户0175WbuX 2022-02-24

  对于工科生,C语言是一门必修课。 标准C(ANSI C) 这个 看似简单 的语言在硬件底层编程、嵌入式开发领域还是稳坐头把交椅。在20年5月份,C语言就凭借其在医疗设备上的广泛应用,时隔五年重回编程语言榜首。

  知识盘点:老师上课不会讲到的C语言知识!补了课的已经面试成功

  同学们在拿到学分之后还有没有使用这门“手艺”呢?

  想做软硬件项目的同学还需要补足哪些知识呢?

  不论是正在学习还是曾经学习过C语言的同学,这篇文章总结的一些要点能提供一个 新的角度来理解C语言的设计理念和特性 。

  一起来看看吧!

  原文链接:

  cnblogs/huxiaoan/p/14749360.html?utm_source=tuicool&utm_medium=referral

  知识盘点:老师上课不会讲到的C语言知识!补了课的已经面试成功

  一共有多少个关键字?这个的确不好说,在C99和C11里都添加了新的关键字,也有的关键字由于过时淡出了我们的视线。下面这些关键字的用法都掌握了吗?

  auto

  它可谓默默无闻,不少人应该知道它没什么用——局部变量默认就是auto类型。除此之外,auto变量存放在动态储存区中的栈区。也就是这种变量时有时无,寿命可变,自动(auto)管理。

  注意:正因为来去自如,创建的局部变量不会自动初始化为零!!切记

  但是,在C++11里auto翻身了,可以用作 类型推导 。比如:

  知识盘点:老师上课不会讲到的C语言知识!补了课的已经面试成功

  可是这和C有什么关系?

  static

  你能想到static的几个用法?有人说是三个,我觉得就两个。

  修饰全局变量或函数时,它的作用是 仅限本文件访问 。C语言里没有命名空间,如果不加static,不同文件里的同名变量会引起混淆,毕竟他们的作用域相同。

  修饰局部变量,成为存放在静态储存区的静态变量。生命周期为整个程序执行过程。与auto不同,静态变量在程序开始之前就初始化完毕。这也就是常说的第三个用法,将局部变量初始化为零。其实这只是变量存放在静态储存区的一个特征,所以不单独拿出来。

  volatile

  大多数学校课程是不会用到它的,接触单片机和多线程就能懂得它的重要性。

  volatile的意思是”易变的、无常的“,名副其实。

  volatile是对变量的修饰,比如 volatile int flag=0; 它是对编译器的提醒:

  ”嘿,这变量是变化无常的,你可小心点!“

  这针对的是编译器的”小聪明“——优化。

  举个例子

  知识盘点:老师上课不会讲到的C语言知识!补了课的已经面试成功

  计算机运算要先把变量从内存加载到寄存器,这一步是耗时间的。编译器一看,前脚我才让flag=1,这个flag还在寄存器里,到下一句判断之间也没有能改变flag的语句,那我不直接用这个寄存器里的flag=1嘛。

  可万万没想到,就在flag=1之后,if之前,来了一次 硬件中断 ,终端回调函数把flag改成0了。

  编译器是料不到的,就认为flag=1。这在很多实际情况下是很恐怖的。

  不仅仅是中断,插入一段汇编,其他线程改变内存都会引起这类问题。

  如果改为 volatile int flag=0; ,凡是用到这个变量, 就会去内存里不怕麻烦地找到它 ,不再偷懒。

  当时我年轻不懂事,一个单片机项目里用中断改变标志位。怎么都不正常,后来哥们让我在标志前面加个volatile就解决了。。。

  __WEAK

  这 不是个关键字 ,这只是GCC的一个特性。看STM32官方固件库的同学应该没少见到它,但它不是C++里virtual那种虚函数。 如果有同名的不带_WEAK前缀的函数,优先使用不带的。

  如果用户自定义了,那就使用用户的,如果没有,那就用默认的。这样方便用户自定义一些回调函数、处理函数。

  相信大家对C语言的 强类型 特性印象非常深刻。尤其是printf的格式化输出和复杂指针的类型。

  程序不就是数据结构+算法,基本类型则是构成数据结构高楼大厦的一砖一瓦。

  char

  冥冥之中,我觉得char类型是最神奇的类型。在C语言标准里char的大小是1 Byte,这是不会变的,也就是sizeof(char)无论在哪都是1。但是:

  知识盘点:老师上课不会讲到的C语言知识!补了课的已经面试成功

  输出是多少?是4,一个int的大小!没错, 字符常量的类型不是char而是int 。

  来放松一下。

  你平时怎么读“char”?反正我是读了好几年的 ”差“ ,后来转念一想,字符的英文是character[?k?r?kt?(r)],那不应该是。。。。其实有三个发音,英文char(煤炭)、car(汽车)、care(关心)都可以。

  float

  浮点数比整形更贴近实际,也不至于出现除法去尾的情况。要注意的是,计算机的浮点数是分立的,有时候1.30会变成1.299999。比如matlab里查看eps(epsilon)可以得到浮点数的最小分度值。(win64下)

  知识盘点:老师上课不会讲到的C语言知识!补了课的已经面试成功

  三者的关系可以说是纠缠不清。

  刚学C都遇到过,函数返回值可以是一个庞大的结构体,却不能是一个简单的古玩论坛数组。可是,数组类型可以是结构体,结构体的成员也可以包含数组,仅仅是组织方式的区别。

  结构体和数组

  举例说明一下,现有结构体struct_a,有成员a、b、c三个。

  知识盘点:老师上课不会讲到的C语言知识!补了课的已经面试成功

  注意最后一种写法,有时候编译器为了对齐,会填充一些地址,导致不连续。不要这样访问结构体成员!

  如果是数组呢?我们常用arr[n]这种方式来访问数组成员,”[]“这个符号的用途是把a[b]变成*(a+b)。请结合例子理解一下。

  知识盘点:老师上课不会讲到的C语言知识!补了课的已经面试成功

  数组和指针

  把数组传入函数时,有两种写法

  知识盘点:老师上课不会讲到的C语言知识!补了课的已经面试成功

  在C里,第一种会自动转化成第二种,所以访问数组本质还是指针。

  教你个窍门:

  int arr[10];

  int* ptr=&arr[-1];

  然后就可以从下标1开始用数组ptr[]。

  知识盘点:老师上课不会讲到的C语言知识!补了课的已经面试成功

  毫无疑问,指针是个麻烦事。比如 char *(*(*(a[2])())() 是一个 包含2个指向返回 指向字符的指针的函数指针的数组 ,几乎很难看出它到底是数组还是指针。

  希望这些要点能帮到你!

  优先与[]结合再与*结合

  指针类型:把声明中指针名称去掉,就得到了指针的类型。

  Int * ptr→int *

  Int(* ptr)[3]→int(*)[3]

  同时注意结合关系,比如下面这个的名称就是ptr[3],而不是上面的ptr

  int *ptr[3]->int *

  所指向的类型:去掉指针名称和一个*

  int*ptr; : 指针所指向的类型是 int

  int ** ptr; : 指针所指向的的类型是 int*

  int(*ptr)[3]; : 指针所指向的的类型是 int()[3]

  指针赋值时,左边指针所指向的类型必须具有右边指针所指向类型的全部限定符,比如

  知识盘点:老师上课不会讲到的C语言知识!补了课的已经面试成功

  C语言绝不是Python那样自备电池的全能型语言,它是一门中级语言。

  标准库函数往往看起来简陋而且有缺陷。

  来了解一下吧。

  知识盘点:老师上课不会讲到的C语言知识!补了课的已经面试成功

  这三个函数的执行顺序是不确定的,C标准把选择顺序的权力交给编译器以便针对各个平台进行优化。

  可以确定的一点是,乘法优先级高于加法。

  可能很多人都知道这个考点,函数参数压栈的顺序是从右至左,右边的表达式会先被运行。

  重点在后面的问号

  C标准对于压栈顺序 并没有明确规定 ,也就是编译器 可以修改成从左至右 的压栈顺序。

  默认的从右至左是为了支持可变参数,用来计算栈的大小。

  早期的 gets() 导致了蠕虫病毒,因为它不检查缓冲区是否越界,其实scanf也有这个问题。标准输入输出有许多设计上的细节需要被了解,比如printf使用%来转义%而不是\ , scanf里的

  并不代表等待一个换行符而是读取并抛弃所有空格......

  这些设计上的特点可能会在意想不到的地方产生出意想不到的效果。所以,为了程序的健壮性,多多了解它们吧。

  预处理是个很好的想法,增强了程序的可移植性和裁剪性。

  不仅仅是常见的#include、#define,它的功能可以非常强大,如果用得好的话。

  #include能做些什么?

  复制,原封不动地复制。

  甚至可以这样:

  知识盘点:老师上课不会讲到的C语言知识!补了课的已经面试成功

  真就是原封不动,但要注意预处理命令是要 在一行的开头,独占一行 。

  如果是 #include<> 则会首先在标准位置(C语言安装位置)搜寻, #include "" 则现在同一文件夹下搜索,找不到再去标准位置搜索。

  在C++里,用#define来定义常量是不被推荐的,因为#define也仅仅是预处理替换,没有类型检查。

  推荐使用const修饰的变量。仁者见仁,两种方法各有特点。

  知识盘点:老师上课不会讲到的C语言知识!补了课的已经面试成功

  “ 看似简单 ”这个描述对于C语言是再恰当不过的。最早的K&R标准只有40页,ANSI C手册则超过了两百页,尽管这样,C语言特性给了编程者极大的自由,衍生出来许多意想不到的用法和Bug。。。

  本文整理的内容不过是冰山一角,还有更多的进阶内容等待探索。

  周虽旧邦,其命唯新。多次的标准更新已经让C语言不再是教科书里的简陋模样。了解新特征,有利于C语言的实际应用。

  希望大家都能够熟练掌握这门 传统艺能 !

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多