C语言基本结构(下)
Every program is a part of some other program and rarely fits.[0]
码字不易,对你有帮助 点赞/转发/关注 支持一下作者
微信搜公众号:不会编程的程序圆
看更多干货,获取第一时间更新
思维导图
在这里插入图片描述
写在前面
如果只是写个人学习总结的博客很容易,简单写一些感悟然后贴上代码走人就可以了,甚至不用校审。但是我命名本系列为【C语言必知必会】帮助你从入门到精通 C语言,那势必要“事无巨细”一些:既要考虑到没有基础的初学者,又不能止于基础。所以本教程适合各类人群学习,只要你看就一定会有帮助。
本教程是本人纯手打并排版,校审由我与我的搭档汤圆君一起完成的。你们看这一篇文章我要写好几个小时。如果文章对你有帮助,请不要“白嫖”。支持一下作者,作者会发更多干货好文。
特别鸣谢:汤圆君(公众号:【Cc听香水榭】 长期更新高质量英语教学)关注她表示对她工作的认可吧!
》 此符号表示该内容以后的章节会讲解,此章节内不要求理解。
简单的程序结构
下面是一个简单的程序,身高是给出的,体重是在程序中得到的,我们输出的是体重与身高/体重的值。
这里我们更注重的是程序的结构而非程序本身。
示例
在这里插入图片描述<figcaption style="line-height: inherit; margin: 0px; padding: 0px; margin-top: 10px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em;">在这里插入图片描述</figcaption>
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 是不同的。
声明变量的理由:
- 把所有变量放在一处,方便读者查找和理解程序的用途。
- 声明变量可以促使你在编写程序之前做好计划(比如你的程序要用什么变量,你可以提前规划)。
- 声明变量有助于发现程序中的小错误,如拼写错误。
- 不提前声明变量,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 函数,我们来看两个不那么复杂的:
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 ,他们分别是变量和表达式(含有常量,变量和运算符的式子),也是指定要被打印的参数(打印到你的屏幕上)。
我们发现,最终我们屏幕上看到的是引号内的内容。我们可以来看一下输出的内容:
我的体重是: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 ,这和我们想的不一样,我们知道结果应该是个小数,那么这是为什么呢?
我想可能的原因有两个:
- %d 将小数转换为整数
- 180 / 160 本身在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;}
输出:
-17179869180.000000
输出并不是我们想要的内容,我们来看一下编译器的警告:
编译器警告:
“printf”: 格式字符串“%d”需要类型“int”的参数,但可变参数 1 拥有了类型“double” “printf”: 格式字符串“%f”需要类型“double”的参数,但可变参数 1 拥有了类型“int”
可以不去理解报错的内容。输出与报错至少说明了一点:
%d 在我的编译器上无法输出浮点型;整型 / 整型 不是浮点型。
那就说明了原因2是对的,即:180 / 160 的值就是 1
为什么 180 / 160 == 1
(180 / 160 的值是 1)呢?
因为 weight 和 height 都整数,它们相除结果取整数(向下取整)。
如何输出 float 类型的浮点数?
printf("%f", 2.0f);
%d
是一个占位符,其作用是指明 num 值的位置。d 代表 以十进制的格式。
还有一点要注意的是,在示例中,第二个输出的整数的参数(height / weight )是一个表达式,我们也可以在程序中添加一个新的变量,然后用这个变量代替上面的表达式作为 printf() 的参数。如:
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)。
同一个声明中可以对任意数量的变量进行初始化。如:
int a = 10, b = 15, c = 20;
上述每个变量都拥有属于自己的初始化式。接下来的例子,只有 c 有初始化式,a,b没有。
int a, b, c = 20;
<small class="footnote" id="footnote-0" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px;">[0]: 每个程序都是其他程序不合适的一部分。</small>
参考资料:《C Primer Plus》《C语言程序设计:现代方法》
本文GitHub已更新,所有教学和练习代码都会上传上去,欢迎 star !
以上就是本次的内容。
如果文章有错误欢迎指正和补充,感谢!
最后,如果你还有什么问题或者想知道到的,可以在评论区告诉我呦,我可以在后面的文章加上你们的真知灼见。
关注我,看更多干货!
我是程序圆,我们下次再见。
网友评论