浅谈C语言入门

计算机和编程语言

计算机

现在我们见到的计算机(电脑),都是由硬件部分和软件部分组成

  • 硬件部分:运算器、控制器、存储器、输入设备和输出设备。
  • 软件部分:分为系统软件和应用软件。
    如果把计算机比喻为一个人的话,那么硬件就表示人的身躯,而软件则表示人的思想、灵魂。二者相互依存,缺一不可,共同构成一个完整的计算机系统。

编程语言

  • 程序就是用特殊的编程语言告诉计算机如何做一件事,计算机能懂的只有二进制,如果我们需要让计算机去做一件事,就需要先找出计算的步骤,计算的步骤即算法,而计算机做的事情就是计算。
  • 首先,把表示计算步骤的程序和计算中需要的原始数据,在控制器输入命令的控制下,通过输入设备送入计算机的存储器存储。其次当计算开始时,在取指令作用下把程序指令送入控制器。控制器对指令进行译码,在经过运算器计算并把结果存放在存储器内。在控制器的取数和输出命令作用下,最后通过输出设备输出计算结果。

为什么要学习算法

人在计算的时候会有各种各样的方式,例如明朝时万户上天,亚历山大斩断绳索之类,但对于计算机来说,他们的智慧并不高,正如其名只是具有极高的计算能力,它们更喜欢枚举,枚举的缺陷就是在大量数据面前极其缓慢,所以为了使其计算的更快,所以我们需要设计算法。

解释与编译

解释:借助某个程序,由这个程序读懂你的程序,按照你所设定的步骤执行。

  • 这个程序会一条一条的执行你的源代码

编译:借助某个程序,由这个程序把你的程序翻译成计算机能懂的语言(机器语言),由计算机执行。

  • 这个程序相当于一个翻译,会一次将你的所有源代码翻译成机器代码,然后再去执行这个机器代码。

如何看待解释语言与编译语言

  • 语言并无翻译与解释之分,只是常用的执行方式,C语言作为编译性语言,也通过C语言的解释器进行解释,python语言作为解释性语言,也可以通过编译器进行编译。
  • 解释性语言的优点:有特殊的计算能力。例如:运行过程中修改源代码。
  • 编译性语言的优点:有确定的运算性能。
  • 编译性语言一般快于解释性语言,其二者的速度的差距在计算机极高的速度下,对于许多程序也没有很大差异。

    为什么要学c语言

    c语言是一种工业语言,即一些专业的人员在做一些非常基础的工作再用此语言,我们学习c语言更看重的是它的开发效率,而不是开发是否便捷方便。
  • 操纵系统
  • 嵌入式系统
  • 驱动系统
  • 底层驱动
  • 图形引擎
  • 图像处理

c语言曾经是工业中使用量最多的编程语言,很多新兴的编程语言在语法上差异不大,当在说某个语言强大的时候,一般来说它是在针对你想要做的事情上有别人写好的库,所以你想要做这件事的时候就很容易。传统导致人们在遇到某个问题通常选择某个语言。而c语言则是处在一个很基础的位置。任何一个语言倘若深入学习,都是需要活到老学到老的。所以我们选择c语言二u们。

c语言的历史

C语言是由B语言发展来的,B语言是由于BCPL发展而来的,BCPL是从FORTRAN发展而来的。
1973年3月,在第三版的Unix上出现了C语言编译器,1973年11月,第四版的Unix完全用C语言重写了。(鸡生蛋,蛋生鸡)

  • 1989年ANSI发布了第一个标准——ANSI C
  • 1990年ISO接受了ANSI的标准 C89
  • 1995年更新标准为C95
  • 1999年更新为C99并沿用至今

编辑并编译C语言

C语言需要编译才能被运行,我们需要一个编辑器把代码记录到电脑,然后通过编译器进行编译运行。两个可以放在一起作为一个程序,这就是所谓的IDE(集成开发环境),推荐使用的一般是DEV-c++,当然大家可以根据自己的喜好去选择大家喜欢的IDE。

第一个c语言程序

  • 避坑指南
  1. 输入法处于英文输入模式
  2. 代码错误
    • 没有分号
    • 缺少括号
    • 关键字错误
  3. 确保文件名称无中文
  4. 确保文件创建正确
1
2
3
4
5
6
7
8
#include <stdio.h>

int main()
{
printf("Hello World!\n");

return 0;
}

c语言程序框架

  • 在学习函数之前所有的代码都是在这个框架下完成的。
    1
    2
    3
    4
    5
    6
    7
    #include <stdio.h>

    int main()
    {

    return 0;
    }

使用c语言做一个计算

1
2
3
4
5
6
7
8
#include <stdio.h>

int main()
{
printf("%d",1+1);

return 0;
}
  • 计算结果如下

注释

注释就是一种解释说明,通常会告诉阅读者自己代码的意思
C语言注释方法有两种:

  • 单行注释: //注释一行
    1
    2
    3
    4
    5
    6
    7
    8
    #include <stdio.h>
    // 这是我编写的第一个c语言程序
    int main()
    {
    printf("Hello World!\n");

    return 0;
    }
  • 多行注释: /* 注释内容 */
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #include <stdio.h>
    /* 这是我编写的第一个c语言程序
    这是我用c语言进行计算的程序 */
    int main()
    {
    printf("%d",1+1);

    return 0;
    }

变量常量

超市找零的程序示例

变量的定义

为什么需要变量?

  1. 有地方放数字
  2. 有办法输入数字
  3. 输入的数字能参与运算
  • 变量是一个保存数据的地方,当我们需要在程序里保存数据时,比如需要记录用户输入的价格时,就需要一个变量来保存它。用一个变量保存了数据,它才能参与到后面的计算中。
  • 变量定义的一般形式就是: <类型名称><变量名称>;
    1
    2
    3
    int price;
    int amount; // 一行定义一个变量
    int price amount; //也可以一行定义多个变量;
  • 变量需要一个名字,变量的名字是一种“标识符”,他是用来识别这个和那个的不同的名字。
  • 标识符的构造规则;标识符只能由字母,下划线组成,数字不可以出现在第一个位置上,C语言的关键字不可以做标识符;

C语言的关键字

关键字如下(无需刻意记忆)
auto :声明自动变量
break:跳出当前循环
case:开关语句分支
char :声明字符型变量或函数返回值类型
const :声明只读变量
continue:结束当前循环,开始下一轮循环
default:开关语句中的“默认”分支
do :循环语句的循环体
double :声明双精度浮点型变量或函数返回值类型
else :条件语句否定分支(与 if 连用)
enum :声明枚举类型
extern:声明变量或函数是在其它文件或本文件的其他位置定义
float:声明浮点型变量或函数返回值类型
for:一种循环语句
goto:无条件跳转语句
if:条件语句
int: 声明整型变量或函数
long :声明长整型变量或函数返回值类型
register:声明寄存器变量
return :子程序返回语句(可以带参数,也可不带参数)
short :声明短整型变量或函数
signed:声明有符号类型变量或函数
sizeof:计算数据类型或变量长度(即所占字节数)
static :声明静态变量
struct:声明结构体类型
switch :用于开关语句
typedef:用以给数据类型取别名
unsigned:声明无符号类型变量或函数
union:声明共用体类型
void :声明函数无返回值或无参数,声明无类型指针
volatile:说明变量在程序执行中可被隐含地改变
while :循环语句的循环条件

常用的变量类型

  • 整型int:用于储存整数
  • 字符型char:用于储存单个字符
  • 单精度浮点型:float:用于储存小数
  • 双精度浮点型:double: 用于储存位数较多的小数

变量的赋值和初始化

变量定义后没有赋值,相当于打开一块存储空间,但里面有什么不知道。所以定义的时候需要进行赋初值。

  • 变量初始化:<类型名称><变量名称>=<初始值>
    1
    int price = 0; //定义一个变量,变量名字是price,类型是int,初始值为0。
  • price=0是一个式子,这里的“=”是一个赋值运算符(有运算符的式子叫表达式),表示将“=”右边的值赋给左边的变量。
  • 在数学中,a=b表示一种关系,即a和b的值一样,而在程序设计中,a=b表示要求计算机完成一个动作:将b的值赋给a。关系是静态的,而动作是动态的。
  • 变量类型:c语言是一种由类型的语言,所有的变量在使用之前必须定义或声明,所有的变量必须由确定的数据类型。数据类型表示变量中可以存放什么样的数据,变量中只能存放指定类型的数据。

变量输入

  • printf用于输出,scanf用于输入
  • 一个scanf可以读入一个数字,也可以读入多个数字
  • 避坑指南
    • 漏写&
      1
      scanf("%d",&price); //要求scanf这个函数读入一个整数,并把读到的结果赋给变量price。

常量

  • 固定不变的数,是常数。直接卸载程序里的数字,称之为直接量:
    1
    int change = 100 -price;
  • 根据编码规范,常量名一般都大写。const是一个修饰符,加在int前面用来给这个变量加上一个const(不变的属性)。这个const的属性表示这个变量的值一旦初始化,就不再修改了
    1
    const int AMOUNT = 100
  • 经常量定义式放在函数中,同时代码修改为
    1
    int change = AMOUNT - price;
    如果试图对常量修改,给它赋值,编译器就会报错。

身高单位换算程序示例

  • 两个整数的运算结果只能是整数,整数运算会自动四舍五入,在c语言中,而带有小数点的数称为浮点数。
  • 当浮点数和整数放在一起运算时,c会将整数转换成浮点数,然后进行浮点数的运算。
  • int是定义整型变量的,定义时把int换成double,可以将它改为浮点数。double就是双精度浮点数,float是单精度浮点数。

表达式

  • 一个表达式是一系列运算符和算子的组合,用来计算一个值
    • 运算符是指进行运算的动作,比如“=” “+” 和 “-”
    • 算子是指参与运算的值,可能是常量,也可能是变量,还可能是一个方法的返回值

计算时间差程序示例

  • hour*60+minute 将单位转换成分钟
  • t/60 小时部分
  • t%60 分钟部分

运算符号的优先级

  • 单目就是只作用于一个变量,即在一个算子上进行取反,平方之类的运算。
  • 在c语言中,赋值是一个运算符(赋值运算符),而在有些语言中,赋值是一个动作
  • 以下列举常用的运算符
优先级 运算符 运算 结合关系 举例
1 + 单目不变 自右向左 a*+b
1 - 单目取负 自右向左 a*+b
2 * 自左向右 a*b
2 * 自左向右 a/b
2 % 除余 自左向右 a%b
3 + 自左向右 a=b
3 - 自左向右 a-b
4 = 赋值 自右向左 a=b

交换变量值

  • 两个变量交换需要借助第三个变量
  • a=5,b=6交换
    1
    2
    3
    t = a;
    a = b;
    b = t;

复合赋值

  • 5个算术运算符,+ - * / %,可以可赋值运算符”=”结合起来,形成复合运算符
复合运算符 举例 运算
+= a += 5 a=a+5
-= a -= 5 a=a-5
*= a *= 5 a=a*5
/= a /= 5 a=a/5
%= a %= 5 a=a+5

递增递减预算符

  • “++ “和 “- -“ 是两个特殊的运算符,它们是单目运算符,但它所作用的算子必须是变量,它们的作用就是给变量加一或者减一
  • a = 5
递增运算符 复合运算符 运算
a ++ a += 1 a = a + 1

a++ 和++a的区别

假设a = 5

  • a++是先运算后自增(先把a值输出再+1):结果a++ = 5, a = 6
  • ++a是先自增再运算(先+1再把a值输出):结果++a = 6, a = 6

++和- -同理

if判断(条件判断)

  • 一个基本的if语句是由一个关键字if开头,跟上括号里的一个表示条件的逻辑表达式,然后是一对大括号“{ }”之间的若干条件语句。如果表示条件的逻辑表达式的结果不为 0 ,就执行大括号中的语句。
    1
    2
    3
    4
    5
    // 如果(im小于0),那么
    if ( im <0 ) {
    im = 60 + im;
    ih --;
    }
  • if判断程序示例
  • 效果展示

if语句

1
2
3
if(条件成立) {

}
  • 关系运算符
运算符 意义
== 相等
!= bu相等
$>$ 大于
$>$= 大于或等于
< 小于
<= 小于或等于
  • 效果展示

优先级

  • 所有的关系运算符的优先级比算术运算低,但是比赋值运算高。

连续的关系运算时从左到右边进行的

  • 效果展示

else语句

超市找零代码示例

  • 不同输入运行结果示例

两数比大小程序示例

  • 方案一
  • 方案二
  • 方案三
  • 运行输出均如下

if语句没有大括号

  • if 语句这一行结束的时候并没有表示语句结束的“;”,而后面赋值语句写在if的下一行,并且锁进了,在这一行结束的时候有一个表示语句结束的“;”。这表明这条赋值语句是if语句的一部分,if句拥有和控制这条赋值语句,决定它是否要被执行。
    1
    2
    if ( a > b )
    max = a;

计算薪水程序示例

判断成绩及格示例

if-else嵌套

  • 当if的条件满足或者不满足的时候要执行的语句也可以是一条if或者if-else语句,这就是if-else嵌套
  • else总是和最近的if匹配

三个数比大小

级联的if-else if

分段函数

x<0,f(x)=1
x=0,f(x)=0
x>0,f(x)=2x

if-else常见错误

  1. 忘了大括号
    解决:永远在if和else后面加上大括号
  • if后面的分号
  • 错误使用==和=

    switch-case语句

    sitch语句可以看作是一种基于计算的跳转,计算控制表达式的值后,程序会跳转到相匹配的case(分支标号)处。分支标号只是说明switch内部位置的路标,在执行完分支中最后一条语句时,如果没有后面的break,就会顺序执行到下面的case中去,直到遇到一个break,或者switch结束。
  • 在else-if级联较多的时候可以选择switch-case语句
  • 控制表达式只能是整数型的结果
  • 常量可以是常数,也可以是常数计算的表达式
1
2
3
4
5
6
7
8
9
10
11
12
switch (控制表达式) {
case 常量:
语句
......
case 常量:
语句
......
case 常量:
语句
......
......
}

while循环

四位数以下判断数的位数程序示例

  • 人可以一眼看出这是几位数,但计算机不能,计算机需要判断数的大小来判断,但是if具有局限性,位数多了就难以实现,代码量庞大。此时就需要while循环。

while循环数位数的算法

  1. 用户输入x;
  2. 初始化n=0;
  3. x = x/10,去掉个位;
  4. n++;
  5. 如果x>0,回到第3部;
  6. 否则n就是结果。

do-while循环

  • 在进入循环的狮虎不做检查,而是在执行完一轮循环体的代码之后,再来检查循环的条件是否满足,如果满足则开始下一轮循环,不满足则结束循环。
  • do-while是在循环体结束之后才来判断条件,while是判断条件后再循环。无论条件满足与否,do-while一定做一次,while可能一次也不做。
1
2
3
4
do
{
<循环体语句>
} while(<循环条件>);

do-while循环实现数位数

  • 我们可以把while翻译为“当”,那么while循环的意思就是:当条件满足时,不断重复循环体内的语句。

计算log的程序示例

小技巧:在while循环后因为一直在进行,会改变x的值,所以当最后需要输出x的时候,可以定义一个变量将x保存下来。

倒计时循环程序示例

  • 在这个程序中共进行了4次循环,循环结束时n=-1。(可通过列举变量的变化进行判断)

猜数游戏程序示例

  1. 计算机随机想一个数,记在变量number里;
  2. 一个负责记次数的变量count初始化为0;
  3. 让用户输入一个数字a;
  4. count++;
  5. 判断a和number的大小关系,如果a大,就输出“大”;如果a小就输出“小”;
  6. 如果a和number是不相等的,程序回到第三步。
  7. 否则,输出“猜中”和“猜中次数”,然后结束

for循环

计算阶乘的程序示例

for循环像一个计数循环:设定一个计数器,初始化它,然后计数器到达某值之前,重复执行循环体,而每执行一轮循环,计数器以一定步进进行调整,比如加一或减一。

for循环

  • for中的每一个表达式都是可以省略的
    1
    2
    3
    4
    for(初轮动作; 条件; 每轮的动作)
    {
    <循环体>
    }
  • 对于一开始的count=10,当count>0时,重复做循环体,每一轮循环在做完循环体内语句后,使得count–。
    1
    2
    3
    4
    for(count=10; count>0; count--)
    {
    <循环体>
    }
  • 循环控制变量i只在循环里被使用了,在循环外面它没有任何作用。因此,我们可以把i的定义写到for语句里面去。(c99)
    1
    2
    3
    4
    for(int i=10; i>0; i--)
    {
    <循环体>
    }

循环的计算和选择

  • 对于以下的循环来说,循环的次数是n,而循环结束以后,i的值是n。循环的控制变量i,是选择从0开始还是从1开始,是判断i<n,还是判断i<=n,对循环的次数,循环结束后变量的值都有影响。
    1
    2
    3
    4
    for(i=0; i<n; i++)
    {
    <循环体>
    }

for和while的循环如何选择

  • 如果有固定次数,用for
  • 如果必须执行一次,用do-while
  • 其他情况用while

循环控制

素数判断程序示例

  • 可以在循环中加break,当不满足的时候直接跳出循环完成判断,减少循环次数。

break和continue对比

  • break:跳出循环
  • continue:跳过循环这一轮剩下的语句进入下一轮循环

循环的嵌套

输出100以内的素数

  • 程序运行效果如下

整齐输出前50个素数

  • 程序运行效果如下

凑硬币

  • 用1角,2角,5角的硬币凑出钱数
  • 程序运行效果如下
  • 只需要一种情况即可,跳出循环

break跳出循环

goto跳出循环

  • 上面为break跳出,下面为goto运行跳转,从如下可以看出两者程序运行效果并无差别,goto的优点在于可以不受限制的灵活跳转,goto语句可以灵活跳转会导致破坏结构化设计风格,若一段代码多次使用goto语句会降低代码的可读性,且goto语句的执行可能会跳过变量的初始化、重要的计算语句等,甚至影响到整个程序的运行。二至使用时候需要进行选择