From 580550f9fb0f299e88a1ed1ed95a430d0b49995e Mon Sep 17 00:00:00 2001 From: hairrrrr <781728963@qq.com> Date: Thu, 5 Mar 2020 18:24:22 +0800 Subject: [PATCH] 3-5 --- C Crash Course/02 Basic Conception/text/02.md | 366 ++++++++++++++++++ 1 file changed, 366 insertions(+) create mode 100644 C Crash Course/02 Basic Conception/text/02.md diff --git a/C Crash Course/02 Basic Conception/text/02.md b/C Crash Course/02 Basic Conception/text/02.md new file mode 100644 index 0000000..3f5cf34 --- /dev/null +++ b/C Crash Course/02 Basic Conception/text/02.md @@ -0,0 +1,366 @@ +## C语言基本结构(下) + +*Every program is a part of some other program and rarely fits.*[^0] + + + +> 码字不易,对你有帮助 **点赞/转发/关注** 支持一下作者 +> 微信搜公众号:**不会编程的程序圆** +> **看更多干货,获取第一时间更新** + +### 思维导图 + +*** + +![在这里插入图片描述](https://img-blog.csdnimg.cn/20200305164948979.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0OTU0MDEw,size_16,color_FFFFFF,t_70) + +### + +*** + + +### 写在前面 + +*** + +### :email:写在前面 + +*** + +如果只是写个人学习总结的博客很容易,简单写一些感悟然后贴上代码走人就可以了,甚至不用校审。但是我命名本系列为【C语言必知必会】帮助你从入门到精通 C语言,那势必要“事无巨细”一些:既要考虑到没有基础的初学者,又不能止于基础。所以本教程适合各类人群学习,只要你看就一定会有帮助。 + +本教程是本人纯手打并排版,校审由我与我的搭档汤圆君一起完成的。你们看这一篇文章我要写好几个小时。如果文章对你有帮助,请不要“白嫖”。支持一下作者,作者会发更多干货好文。 + +特别鸣谢:汤圆君(公众号:【Cc听香水榭】 长期更新高质量英语教学)关注她表示对她工作的认可吧! + +》 此符号表示该内容以后的章节会讲解,此章节内不要求理解。 + + + +### 简单的程序结构 + +*** + +下面是一个简单的程序,身高是给出的,体重是在程序中得到的,我们输出的是体重与身高/体重的值。 + +这里我们更注重的是**程序的结构**而非程序本身。 + + + +示例 + +![在这里插入图片描述](https://img-blog.csdnimg.cn/20200305165553855.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0OTU0MDEw,size_16,color_FFFFFF,t_70) + + +#### 1. 类型 + +> 每一个变量都有**类型**(type)。类型用来描述变量的数据的种类,也称**数据类型**。 + +数值型变量的类型决定了变量所能存储的最大值与最小值,以及是否允许小数点后出现数字。 + +示例中只有一种数据类型:`int` + +> **int**(integer):即整型,表示整数。 + +数据类型还有很多,目前除了 int 以外,我们只再使用另一种: + +> **float**(floating-point): 浮点型,可以表示小数 + +**注意**:虽然 float 型可以带小数,但是进行**算术运算**时,float 型要比 int 型慢,而且 float 通常只是一个值的近似值。(比如在一个float 型变量中存储 0.1, 但其实可能这个变量的值为 0.09999987,这是舍入造成的误差) + +*题外话:我当时学的时候,就没有人告诉我这些知识,你们如果现在是初学,我都感觉到羡慕,你们要少走多少弯路啊!* + + + +#### 2. 关键字 + +> int 与float 都是C语言的**关键字**(keyword),关键字是语言定义的单词,**不能用做其他用途**。比如不能用作命名函数名与变量名。 + +关键字:*斜体代表C99新增关键字* + +| auto | enum | unsigned | break | extern | +| ---------- | -------- | -------- | ---------- | ------------ | +| return | void | case | float | short | +| volatile | char | for | signed | while | +| const | goto | sizeof | continue | if | +| static | default | struct | do | int | +| switch | double | long | typedef | else | +| register | union | | | | +| *restrict* | *inline* | *_Bool* | *_Complex* | *_Imaginary* | + +如果关键字使用不当(关键字作为变量名),编译器会将其视为语法错误。 + + + +> 保留标识符(reserved identifier):下划线开头的标识符和标准库函数名(如:printf()) + +C语言已经指定了这些标识符的用途或保留了它们的使用权,如果你使用它们作为变量名,即使没有语法错误,也不能随便使用。 + +#### 3. 声明 + +> **声明**(declaration):在使用变量(variable)之前,必须对其进行声明(为编译器所作的描述)。 +> +> 声明的方式为:数据类型 + 变量名(程序员自己决定变量名,命名规则后面会讲) + +示例中的 `int weight`完成了两件事情。第一,函数中有个变量名为 weight。第二,int 表明这个变量是整型。 + +编译器用这些信息为变量 weight 在内存中分配空间。 + + + +**C99** 前,如果有声明,声明一定要在语句之前。(就像示例那样,函数体中第一块是声明,第二块才是语句。) + +C99 和 C11 遵循 C++ 的惯例,可以把声明放在任何位置。即可以使用时再声明变量。以后C程序中这种做法可能会很流行。**但是目前不建议这样。** + + + +就**书写格式**而言,我建议将声明全部放在**函数体头部**,声明与语句之间**空出一行**。 + + + +#### 4. 命名 + +> weight,height 都是**标识符**,也就是一个变量,函数或其他实体的名称。因此,声明将特定标识符与计算机内存的特定位置联系起来,同时也就确定了存储在某位置的信息类型或数据类型。 + + + +给变量命名时要使用有意义的变量名或标识符。如果变量名无法清楚的表达自身的用途,可以在注释中进一步说明,这是一种良好的编程习惯与编程技巧。 + +C99 与 C11 允许使用更长的标识符,但是编译器只识别前 63个字符。*对于外部标识符,只允许 31 个字符*。事实上,你可以使用更长的字符,但是编译器可能忽略超出的部分。(比如有两个标识符都是 64 个字符,但只有最后一个字符不同。编译器可能会视其为同一个名字,也可能不会。标准并未定义在这种情况下会发生什么。) + + + +> 命名规则:可以用小写字母,大写字母,数字和下划线(_)来命名。**名称的第一个字符必须是字符或下划线,不能是数字** + +**操作系统和C库经常使用一个下划线或两个下划线开始的标识符(如:_kcab),因此最好避免在自己的程序中使用这种名称。(避免与操作系统和c库的标识符重复)** + +C语言的名称区分大小写。即:star,Star,STAR 是不同的。 + + + +**声明变量的理由**: + +1. 把所有变量放在一处,方便读者查找和理解程序的用途。 +2. 声明变量可以促使你在编写程序之前做好计划(比如你的程序要用什么变量,你可以提前规划)。 +3. 声明变量有助于发现程序中的小错误,如拼写错误。 +4. **不提前声明变量,C程序编译将无法通过** + + + +#### 5. 赋值 + +> 赋值(assignment):变量通过赋值的方式获得值。 + +示例中,`weight = 160; `是一个 **赋值表达式语句**。意思是“把值 160 赋给 变量 weight”。 + +在执行 `int weight;`时,编译器在计算机内存中为变量 weight 预留的空间,然后在执行这行代码时,把值存储在之前预留的位置。可以给 weight 赋不同的值,这就是 weight 之所以被称为变量的原因。 + +**注意:** + +- 该行表达式将值从右侧赋到左侧。 + +- 该语句以分号结尾。 +- `=` 在计算机中不是相等的意思,而是赋值。我们在读 `weight = 160; `时,我们应该这么读:“将 160 赋给 weight” +- `==`表示相等 + + + +#### 6. printf() 函数 + +`printf(“我的体重是:%d斤\n,身高与体重的比为:%d”, weight, height / weight);` + +这是我们示例中的 printf 函数,我们来看两个不那么复杂的: + +```c +main(void); +printf("Hi"); +``` + + + +首先,printf() 的 **圆括号**是不是很像 main() ?这表示 printf 是一个函数名,它也是一个函数。圆括号内的内容是从 main() 函数传递给 printf() 函数的信息。该信息被称为**参数**,更确切的说,是**实际参数**(actual argument),简称**实参**。 + +既然是函数,它其实也是像我们看到的 main函数一样,也有函数头和函数体。 + +printf() 函数是一个库函数,库函数我们上一节讲函数种类时说过,这是一种不需要程序员去写的,只需要引用头文件 `stdio.h`就可以直接使用的。但是我们应该知道这一点,详细情况我们后面会说讲。 + +**当程序运行到 printf() 函数这一行时,控制权被转给了printf()函数。函数执行结束后,控制权被返回至主调函数(calling function),该例中是 main()** 。 + + + +printf() 函数的作用是向我们的显示器输出内容。 + +此例中,printf() 函数的括号内 分为两部分,一部分在双引号内,另一部分在双引号外,它们中间以逗号隔开。双引号外有两个参数 weight 和 height / weight ,他们分别是变量和**表达式**(含有常量,变量和运算符的式子),也是指定要被打印的参数(打印到你的屏幕上)。 + +我们发现,最终我们屏幕上看到的是引号内的内容。我们可以来看一下输出的内容: + +```c +我的体重是:160斤 +身高与体重的比为:1 +``` + + + +我们发现:首先引号内的 `%d` 和`\n`并没有被输出,`%d`的位置被替换成了一个整数。为什么会这样呢? + +> `\n`代表**一个换行符(newline character)**。对于 printf 函数来说,它的意思是:“**在下一行的最左边开始新的一行**”。 +> +> 也就是说换行符和在键盘上按下 Enter按键相同。 +>既然如此,为何不在键入 printf() 参数时直接使用 Enter键呢?因为编辑器可能认为这是直接的命令,而不是存储在源代码中的指令。换句话说,如果直接按下 Enter键,编辑器会退出当前行并开始新的一行。但是,换行符会影响程序输出的(显示)格式。 + +换行符是一个**转义序列**(escape sequence)。转义序列用于难以表示或无法输入的字符。如,`\t`代表 Tab键,即制表符。`\b`代表 Backspace键,即退格键。我们在后面会继续讨论。 + +这样就解释了为何一行的printf() 函数会输出两行。 + + + +*以下这部分不能理解可以只看结论,能理解更好。* + +在解释 %d 之前我们先来看一下,weight 和 height / weight 所代表的值。 + +weight 是被赋值为 160 的,所以 weight 的值就是 160 + +C语言中,`/`表示除法, `*` 表示乘法。 + +那么 height / weight 的值是多少呢?我们现在不知道这个表达式的值是多少,但是我们知道这个它肯定代表 180 / 160 + +而最终输出的值是 1 ,这和我们想的不一样,我们知道结果应该是个小数,那么这是为什么呢? + +我想可能的原因有两个: + +1. %d 将小数转换为整数 +2. 180 / 160 本身在C语言中的值就是整数 + +我们来测试一下: + +```c +int main(void) { + + int a = 3; + int b = 2; + float c = 1.1f;//f 表示1.1是浮点数 + + printf("%d\n", c);//%d 用来输出整型 + printf("%f\n", a / b);//%f 用来输出浮点型 + + return 0; +} +``` + +输出: + +```c +-1717986918 +0.000000 +``` + +输出并不是我们想要的内容,我们来看一下编译器的警告: + +编译器警告: + +```c + “printf”: 格式字符串“%d”需要类型“int”的参数,但可变参数 1 拥有了类型“double” + “printf”: 格式字符串“%f”需要类型“double”的参数,但可变参数 1 拥有了类型“int” +``` + +可以不去理解报错的内容。输出与报错至少说明了一点: + +**%d 在我的编译器上无法输出浮点型;整型 / 整型 不是浮点型。** + +那就说明了原因2是对的,即:**180 / 160 的值就是 1** + + + +为什么 `180 / 160 == 1 `(180 / 160 的值是 1)呢? + +因为 weight 和 height 都整数,它们相除结果取整数(向下取整)。 + + + +如何输出 float 类型的浮点数? + +```c +printf("%f", 2.0f); +``` + + + +>`%d`是一个占位符,其作用是指明 num 值的位置。d 代表 以十进制的格式。 + + + +还有一点要注意的是,在示例中,第二个输出的整数的参数(height / weight )是一个表达式,我们也可以在程序中添加一个新的变量,然后用这个变量代替上面的表达式作为 printf() 的参数。如: + +```c +int main(void) +{ + int height = 180; + int weight, scale;//scale:比例 + weight = 160; + scale = height / weight; + printf(“我的体重是:%d斤\n,身高与体重的比为:%d”, weight, scale); + return 0; +} +``` + + + +合理的使用表达式作为函数的参数可以简化程序。 + +也说明**在任何需要数值的地方,都可以使用具有相同类型的表达式**。 + + + +#### 7. 初始化 + +当程序开始执行时,某些变量会被自动设置为0,而大多数不会。没有默认值并且尚未在程序中被赋值的变量时未初始化的(uninitialized)。 + +如果试图访问未初始化的变量,可能会得到不可预知的值。在某些编译器中,可能会发生更坏的情况(甚至程序崩溃)。 + + + +我们可以用赋值的办法给变量赋初值,但还有更简洁的做法:在变量声明中加入初始值。 + +例如示例中的 `int height = 180`数值 180 就是一个**初始化式**(initializer)。 + + + +同一个声明中可以对任意数量的变量进行初始化。如: + +```c +int a = 10, b = 15, c = 20; +``` + +上述每个变量都拥有属于自己的初始化式。接下来的例子,只有 c 有初始化式,a,b没有。 + +```c +int a, b, c = 20; +``` + + + +*** + +[^0]: 每个程序都是其他程序不合适的一部分。 + +*参考资料:《C Primer Plus》《C语言程序设计:现代方法》* + + + +> 本文GitHub已更新,所有教学和练习代码都会上传上去,欢迎 star ! +> +> https://github.com/hairrrrr/C-CrashCourse + + + +*** +以上就是本次的内容。 + +如果文章有错误欢迎指正和补充,感谢! + +最后,如果你还有什么问题或者想知道到的,可以在评论区告诉我呦,我可以在后面的文章加上你们的真知灼见。 + +**关注我**,看更多干货! + +我是程序圆,我们下次再见。 +