目录
前言
以下内容均为个人粗浅的理解,因人而异,不一定准确,请选择性接受!
作为第一章,也是学习C语言最开始的内容,大多为基本概念的普及。为了保证内容的全面,课本中对于每个部分都进行了罗列和详细的解释。但是作为非计算机专业的学生:目标只是用C语言来写一些简单的程序,甚至有些人在期末考试完之后再也不想碰这个东西,其实很多细节的地方不必研究得过于深入。
因此在接下来的内容里我会根据自己的理解选择性的删除一些课本中个人认为不太重要的地方进行删减。
对于里边涉及到的很多并不常用的东西,只用做到了解大概,知道在哪里能够查到即可【课本上涉及到的很多表格】。对此章节知识点的整理的目的更多的是整理成文、便于查阅,而非在整理的过程中记住这些内容。
本章速览
- 本章内容:本章主要介绍
C
语言入门的最基本内容,包括程序的结构,数据类型和运算符。 - 目标要求:对于初学者而言只需要简单了解,能自己独立的写出一段程序,在后续的章节学习中遇到能有大致印象返回查阅即可。而处于期末复习阶段的要求则是,在只看目录的情况下,能够大致的回忆出每个部分所包含的内容,以及侧重点,即算复习目标达成。
- 学习方式:不要局限于本章,作为总论章节,需要结合其他章节一起学习。在学习其他章节的过程中,寻找总论中提到了的内容。
1. C程序的结构
1.1 万恶之源:Hello Word!
相信大多数人的程序学习都是从输出Hello Word!
开始的。在准备好编译环境的情况下,使用C语言输出Hello word!
的代码如下:
#include<stdio.h> //预处理语句
//下边的内容统称为函数
int main() //函数头
{
printf("Hello Word!"); //输出语句
return 0; //返回值
}
//大括号中的语句为统称为函数体
通过这样一个可以说是最简单的代码,我们可以大概了解C程序的基本结构。
1.2 基本结构:程序由函数组成
其实即使现在基本上快学完了一遍课程内容,外加对照着教材,感觉自己也不能很清楚的说明C程序基本的结构到底是什么。不过还是那句话:这并不影响我们正常的编写程序。
通过上边的例子(一个输出"Hello word!"的程序),我们可以看出:一个程序由预处理语句、函数语句、注释组成。
- 预处理语句:简单的理解就是,写在文件最开头函数之前的那些语句。
- 注释:写在
"//"
后边对程序进行解释语句。 - 函数:意思就是给一个输入,能够返还一个输出的东西。
同时,我们可以看出,函数包括函数头和函数体两个部分,其中:
- 函数头:是对函数各种信息的声明。
- 函数体:即函数的主题部分,由各种语句组成。
大概的情况就像如下的思维导图:
还需要说的是:
- 一个程序只能有一个主函数,但是可以有多个子函数。
- 一个函数只能有一个返回值,但是可以通过指针改变多个值。
不过这些内容后续遇到的时候再进行说明。
如果不能准确的表述出C程序的基本结构,个人觉得没太大关系,因为这并不会对你书写程序造成太大的影响。【不过可能会对考试成绩造成影响】
1.3 编写规则:写好程序的第一步
在刚开始接触程序的时候,由于不了解(或者说是不熟悉)程序的编写规则,我经常写出很多连编译都无法通过的程序。在此列出一些最为基础的,后边主要是在程序例子旁边进行提醒,如果有机会可能单独开一篇来总结。
- 每条语句的结尾都加上
";"
(除开预处理语句)。
其实大家都知道这个规则,只是在最开始的时候,很容易没注意到或者是忘记了。
- 括号
"{}"
需要一一对应
如果是有自动补全功能的编译器还好,那种不带自动补全的编译器,并且嵌套较多的情况,很容易因为忘记补充
"}"
而导致编译不能通过。
【字码到这里不禁想起了被LaTex
输入公式暴打的时光】
2. C语言的基本数据类型
刚开始写
C
的时候,我很怀念matlab
的无拘无束。而现在,我在写matlab
代码的时候都会下意识的先输入int
。
C语言的数据类型包括:基本(内置)数据类型和构造数据类型。
2.1 数据的表示
C语言数据的基本构成成分包括:字符集、标识符、保留字、常亮、变量、运算符等。
- 字符集:就是我们平时较常用的那些字符。
- 大小写英文字母
- 数字和特殊字符:
'+'
、'-'
、'='
- 不可印出字符:空格、换行符、制表符
- 标识符和保留字:一些被赋予了意义的字符或者字符串。按照系统默认和用户定义分为系统保留字和用户标识符。
- 系统保留字(关键字):
char
、if
、sizeof
【特殊的标识符】 - 用户标识符:自己有定义且符合命名规则即可。
- 只能由字母、数字、下划线构成
- 第一个符号不能是数字
- 区分大小写
- 不能是系统保留字【别人更先来好吧】
- 系统保留字(关键字):
- 常亮和变量:大家都懂,不多赘述
2.2 基本数据类型
C语言的基本数据类型有四种:基本类型、指针类型、空类型、构造类型。
具体情况在思维导图中列出,在此不多赘述,其中绿色标星的为现阶段【非专业本科入门课程期末考试】较为常用的的数据类型。
通过一个常见的例子:计算摄氏温度,可以了解C程序变量定义最基本的写法。【这个一个自认为十分详细适合零基础观看的帖子】
2.2.1 各类型的变量可以表示的范围
关于每种类型对应的范围,个人认为能够根据字节数计算便可,故具体对应值在此略去不表。
只需记住:
- 一个字节有8个bit,每个bit可以表示一个0或者1。
- 通过排列组合可以算出能表示的数的个数。
- 根据数据类型进行对半分配。【分配时0算正数】
以int
为例:
- 已知
int
有四个字节。【可通过sizeof(int)
来求】 - 也就是说,对应 4 × 8 = 32 4\times8=32 4×8=32bit
- 可以表示 2 32 2^{32} 232个数,其中正数负数各 2 31 2^{31} 231个。【0算正数】
- 故
int
可以表示的数的范围是 [ − 2 31 , 2 31 − 1 ] \left[-2^{31},2^{31}-1\right] [−231,231−1]。
2.2.2 输入输出的格式对应的控制字符
输入输出函数的使用:
- 格式化标准输入函数调用:
scanf("对应控制字符",变量地址);
- 格式化标准输出函数调用:
printf("对应控制字符",变量);
具体的函数使用方法,通过一个例子进行解释。除此之外,值得分享的是,我在刚开始编写程序的过程中犯过的一些错误:
scanf
函数在调用参数时忘记取地址,如:
int x;
scanf("%d", x); //错误:忘记对变量取地址
scanf("%d", &x); //正确演示
由于地址的本质其实也是一个数,所以这样的错误编译器并不一定能够检查出来,但是会导致无法将值输入到变量。
scanf
函数在输入多个值中间加一些诡异的符号,如:
int x1,x2;
scanf("%d,%d",&x1,&x2); //错误示范:中间加入逗号
scanf("%d %d",&x1,&x2); //正确示范:空格分隔
scanf("%d%d",&x1,&x2); //正确示范:不加分隔符号
其实也不能说用
,
进行分隔是错误的【很多情况下可以用这种方法达到不录入某些符号的目的】,只是这个操作比较违反习惯:
scanf
在读入数据的时候需要严格的按照""
中的格式,如果用第一种写法输入数据的话,在输入数据的时候需要按照同样的格式(用英文,
)将数据隔开。而如果自己在输入数据的时候往往习惯使用空格隔开数据,这会造成数据无法输入成功的现象。
在使用printf
和sacnf
对变量进行输入输出的时候,需要保证数据类型(输入输出格式)和控制字符相对应,具体情况如下
输出格式 | int | long | short | unsigned | float | double |
---|---|---|---|---|---|---|
控制字符 | %d | %ld | %hd | %u | %f | %lf |
输出格式 | 8进制 | 10进制 | 16进制 | 科学计数 | char | 字符串 |
控制字符 | %o | %d | %x | %e | %c | %s |
3. C语言的基本运算符和表达式
3.1 基本运算符
个人理解的运算符就是:用于对变量或者常量进行运算的符号,基本上可以说就是我们在编写程序中最常用的那些东西。
3.1.1 运算符的类型
运算符可以分为以下十类:
- 算数运算符:
+
、-
、*
、/
- 关系运算符:
>
、<
、>=
、<=
- 逻辑运算符:
&&
、||
、!
- 位运算符:咱没怎么用过
- 赋值运算符:
=
- 条件运算符:
?:;
- 逗号运算符:一个取名非常直白的运算符
- 指针运算符:
&
、*
sizeof
运算符:一个取名和逗号运算符一样直白的运算符- 特殊运算符:
()
、[]
最开始我对于逗号运算符(
,
)和条件运算符(?:;
)都很不屑一顾【其实是因为用起来不熟悉】。后来无意间发现如果能够熟练的运用这些运算符,代码写起来代码将会简洁很多,于是踏上了一条不归路。
3.1.2 优先级和结合性:磨人的小妖精
一个小故事:
故事要从两个月以前说起,那个时候我刚开始接触C程序,由于涉世未深还未曾受过程序的毒打。我一直在快乐的学习C语言,直到那一天:当时我正在开心的上课,突然一个好兄弟丢给了我一个问题:这段代码(
int x=4;z=--x*--x*--x
),z
的取值是多少?
这道题直接把当时连a++
和++a
都分辨不清楚的我,给吓得一愣一愣的。
那天我通过查阅资料、运行程序、修改数值、增减括号等一系列方法,观察输入输出值的变化,研究了整整几个小时,也没能搞得很清楚其中的关系【因为和书上介绍的优先顺序有点对不上】,以至于给我幼小的心灵留下了阴影。直到现在我已经能将
a++
和++a
区分得很清楚明白,但是实话实说这个题我还是不太清楚。不过我心里已经没有阴影了,因为:只有和自己过意不去的人才会这样写代码。虽然运算符的优先级我也只懂个大概,但是那天教会了我一件事情——自己写代码就好好写,搞不清楚的地方就加括号!
常见运算符优先级:
由于内容比较同质,且并不存在太大的争议,所以我直接在C语言中文网复制了这个表格过来,侵权删除。
优先级 | 运算符 | 结合律 |
---|---|---|
1 | 后缀运算符:[] () · -> | 从左到右 |
2 | 一元运算符:++ -- ! ~ + - * & sizeof | 从右到左 |
3 | 类型转换运算符:(类型名称) | 从右到左 |
4 | 乘除法运算符:* / % | 从左到右 |
5 | 加减法运算符:+ - | 从左到右 |
6 | 移位运算符:<< >> | 从左到右 |
7 | 关系运算符:<<= >>= | 从左到右 |
8 | 相等运算符:== != | 从左到右 |
9 | 位运算符 AND:& | 从左到右 |
10 | 位运算符 XOR:^ | 从左到右 |
11 | 位运算符 OR:| | 从左到右 |
12 | 逻辑运算符 AND:&& | 从左到右 |
13 | 逻辑运算符 OR:|| | 从左到右 |
14 | 条件运算符:?: | 从右到左 |
15 | 赋值运算符:= += -= *= /= %= &= ^= |= <<= >>= | 从右到左 |
16 | 逗号运算符:, | 从左到右 |
在此说明两点:
- 一元运算符中的
*
是指针的运算符,而非乘除里的乘号。 - 逻辑运算符里的
&&
和||
虽然认为这俩是并列的,但是前者的优先级却更高。
个人认为不用刻意去记,虽然我上次看这个表格还是两个月前刚学习的时候,但是因为平时经常都在用,以至于我现在记忆中这些运算符的先后顺序居然都是正确的。
3.1.3 需要掌握的运算符
- 算术运算符:一些
+
、-
、*
、/
、%
的相关内容
作为正常人最熟悉的运算符,需要注意的事项并不太多:
1. 关于优先级:先乘除后加减,大家都懂【%
运算和*
、/
运算统计】
2. 关于数据类型:变量之间的运算遵循以下原则:
a. 同级的数据运算会保留当前级别的精确度
b. 不同的数据类型相互运算会变成精确程度更高的数据类型
比如说,如下程序:那么
y
的值应该是多少呢?int x1 = 1 x2 = 2; double y = x1/x2;
刚开始学习的时候可能很多人会认为
y = 0.5
;因为作为double
类型,y
能当得起0.5
的地位。但是稍微老练点的选手就会知道y
的值应该是0.0
,原因是:
x1
和x2
都是int
类型的数据,x1
和x2
运行的结果也应该是int
类型的数据- 也就是说
x1/x2 = 0.5
,但是int 0.5 = 0
【int
类型数据直接去掉小数取整】- 此时
y
的值相当于是double 0 = 0.0
如果需要让
y = 0.5
,可以进行强制转换:注意优先级
y = 1.0*x1/x2;
:这样的效果的可以先让x1
变成浮点型,也是最简单的转换方法y = double (x1)/x2;
:这样稍微麻烦些,但是效果是一样的
-
自加自减运算符:神奇的
++
和--
关于自加自减运算符的内容,我在另一篇博客《a++和++a的区别》中进行了详细的说明。
如果需要就点击跳转,在此不进行更多的说明。 -
复合赋值运算符:
+
的加强版+=
就我们目前所学的复合运算符而言,和算数运算符的区别不大,只是一种简化的记录形式,如:
1.x += a;
:实际上想说的是x = x+a;
2.x -= a;
:实际上想说的是x = x-a;
3.x *= a;
:实际上想说的是x = x*a;
4.x /= a;
:实际上想说的是x = x*a;
只用记住一点即可:x 运算= a
实际上就是x = x运算a
。 -
逗号运算符:日用而不知
对于逗号运算符的学习,老实说,在自开始学习的时候,我并没有看太明白书上的内容,外加
平时也不怎么使用这个运算符,所以日子就这样过着,安安稳稳的过着一天又一天。而那段时间我对逗号运算符的理解一直是下面这样的,我用一段程序进行说明:
在看答案之前不妨先自己想想,x,y,z
输出的值到底是多少?
#include <stdio.h>
int main(){
int x,y,z;
x = 1, 2, 3, 4;
y = (1, 2, 3, 4);
z = (z=2, z*5, z+3);
printf("x=%d, y=%d, z=%d",x,y,z);
}
输出的结果是x=1,y=4,z=3
,在这里提供一个阅读逗号表达式的小技巧:将所有的逗号看成分号(;
)加换行\n
;而如果带有括号的,则在最后一行进行赋值【因为=
的优先级和顺序】,这样原本的程序就会变成:
#include <stdio.h>
int main(){
int x,y,z;
//计算x的值
x = 1;
2;
3;
4;
//计算y的值
1;
2;
3;
y = 4; //最后一个参与赋值
z=2;
z*5;
z = z+3; //最后一个参与赋值
printf("x=%d, y=%d, z=%d",x,y,z);
}
这样可以很容易看出x,y,z
所对应的取值。
而真正让我对逗号运算符发生改观的是老师一次上课的PPT:
if (k! = i) t = v[i], v[i] = v[k], v[k] = t;
这让当时稚嫩的我看得虎躯一震,甚至一度怀疑老师PPT上的内容错了。因为我平时写数值交换的函数都是要写三行的。当我反应过来这是逗号表达式的时候,我低下头向它承认了自己的错误。因为这种写法,可以让原本好几行的内容,全部写在一行,大大的减少了代码的长度。自此我的代码风格开始走上了一条不归路:在有一段时间,我的代码一度是这个样子的。【小朋友们千万不要模仿】
3.2 常用的库函数
此处依旧坚持自己的观点:用的多了就会了,因此不做过多解释
如果存在不清楚的,通过百度可以快速的查找到。
math.h
- 绝对值函数:
abs(int x)
【对于浮点数要用fabs
】 - 开方函数:
sqrt(double x)
- 对实数去余数:
fmod(double x, double y)
- 指数函数:
pow(int x, int y)
【x
的y
次方】
后记
从2020 04 29
到2020 05 04
终于更新完毕:到此为止大概6000个字,不算多,但是配合跳转内容,以及图表、代码,还是存在一定的工作量。
由于内容较多,同时还希望做得尽可能的完善【配套例题的跳转】所以编写,估计后边章节的编写依然只有以这个速度慢慢磨。不过尽量保证在期末考试(大概在6月中旬)之前更新完毕,便于期末复习。
所说内容属于个人观点:由于本身是非专业出身的初学者,并不能保证内容的完全正确,若有错误请见谅,并且欢迎指出!