C语言总结项目和入门——前言与基础上

时间: 2023-08-15 admin 互联网

C语言总结项目和入门——前言与基础上

C语言总结项目和入门——前言与基础上

C语言总结项目和入门

  • 一、 前言与运行环境
  • 二、计算机语言
    • 1.码制与数制
    • 2.指令和语言
  • 三、C语言基础上(从数据到程序)
    • 1. 数据
    • 2.运算
    • 3.语法

  在下也是个自学了一点C语言的小菜鸡,写本栏目一方面是为了自己复习使用,另一方面也是希望能让大家快速了解C语言,写的相当随意,很多内容都是自己的理解,就算类似于轻科普的内容吧,如有错误请各位读者指正,谢谢大家。
  本篇文章旨在用最简单的语言讲述C语言的基本语法和内容,力求大家都能看懂,能在最短的时间内入门。
  本文章不含算法,小白也可以放心食用(因为我也不会(~ ̄▽ ̄)~)
  推荐课程:视频——小甲鱼C语言教程;书籍:谭浩强《C程序设计》
  话不多说,让我们开始吧!


一、 前言与运行环境

1.关于C语言的背景知识和应用领域读者可自行搜索查看,不在本栏目的讲述范围。
2.本栏目所有程序使用Dev-C++ 5.11版本,64位windows10环境下运行。

二、计算机语言

1.码制与数制

  大家都知道,计算机只能识别0和1,要实现最简单的加减法,就必须将待加减的数字用0和1表示,也就是二进制(逢二进一)。待加减的数字用0和1表示这一过程成为编码,编码方式有很多,比如常见的恒权码8421BCD码,当然也有非恒权码如格雷码(所谓的恒权,就是指每一位的权重是恒定的)。如0111B在8421中代表(0x23+1X22+1x21+1x20=7),在格雷码中则变成了5。其对应的编码规则如下:

  由此可以看出,编码只要能相互区分,都是可以的,其重点就是在于用不同的编码组合表示不同的现实情况,如表示现实中的十进制数、表示现实中的逻辑状态(时序逻辑电路)。
  当然还有很多编码方式,这里就不一一列举了,相关知识可以查看数电的相关知识。
  接下来说一说数制,我们已经将十进制数表示出来了,也就是说计算机能认得这些由0、1表示的数了,那么这些数的四则运算是怎样实现的呢?3+4=7这个等式在计算机是如何实现的?
  首先,将3、4用二进制表示,即0011B(3)和0100B(4),然后用小学二年级的列竖式的方式,对位相加,再加低位的进位(注意,是逢二进一,而不再是逢十进一)当然本例中没有进一的情况,可以得到下面的数0111,也就是7。

  注意,要选用相同的码制进行运算,得到的结果也是同码制下的结果,用8421码和5211码加出来的结果是没有意义的。
  如果存在最高位进位的情况,如9+7=16,用二进制运算1001+0111=?,由上面的方法,可以得到的1 0000的结果,你会发现,结果比原运算数多了一位,原运算数表示为4位,但结果需要5位才能表示,如果仍用4位表示,会得到0000B(0)的错误结果,其原因是在4位情况下是以16为模的,超出就会从头循环,如下图从9往后数7个,就会回到0。在微机中,如果运算超出了最大能够表示的范围,如在4位情况下无法表示16,计算机会发出一个溢出的中断,当然如果实际上计算机是8位的,5位的结果当然是可以表示的了。

  在计算机中常说的64位操作系统是指可以同时运算64位的数据,即0到2^64-1的无符号数。可以看到现代计算机能计算的数的范围是相当大的。
  问题来了,减法是如何实现的,大家可以发现,编码的时候都是对非负数编码的,我们秉着“减一个数就是加上它的相反数”的原则,就可以将加减法统一。所以减法的问题就变成了如何得到一个二进制数的相反数。
  这里介绍目前计算机中使用的编码方式。
  首先,我们可以在原来的基础上多弄一位出来表示符号,如用0 0010表示+2,用1 0010表示-2,这种编码称为原码,但这种编码看起来没啥问题,其实问题很大,读者将上面两个数相加,会发现+2+(-2)= 1 0100B,即为-4,并不等于0,说明这种编码对运算是不相容的,同时,会出现1 0000B(-0)和0 0000B(+0)的区别,这种区别在现阶段是没有意义的,或者说是不必要的。产生这种问题的原因是原码是混合编码,即用符号+数制的方法表示,而运算只是针对数制,所以-2+(+2)只对数制部分相加即2+2=4,前面符号不管怎么变化,结果都不会为0。
  要想真正实现减法,需要将正负隐藏在数制中,即大家所知的补码。
  补码是用最高位代表负权值,其余各位代表正权值,我认为这句才应该是补码的定义,大家可能学的都是什么“求反加1”的法则,当然是正确的,但那终究是规律,不好把握本质。这句话说起来比较抽象,举个栗子。
  4位二进制数从0000到1111,拿1010出来,从上面的知识我们知道在无符号数8421BCD中表示10,在原码中,最高位表示符号,剩下的表示数值,则表示-2,在补码中,最高位表示负权值,什么是负权值,就是-1x2?,上面1010最高位的位权是3,即为23=8,但最高位表示负,则这一位表示的数就是-23,即-8,后面都表示正权值,即为0x22+1x21+0x20=+2,所以这个补码表示的数是-8+2=-6。整体运算过程如下:
  -1x23+0x22+1x21+0x20=-6。
  同样的,可以说明1111表示-1:-1x23+1x22+1x21+1x20=-8+7=-1。
  补码还有很多性质,这里选一些简单介绍一下。
  首先,在补码状态下的减法运算,在舍弃最高位进位的情况下结果是正确的,如+6(0110)+(-6)1010=1 0000,仍保留4位,即为0000B(0)。同时,+0和-0变一个0,因为1000表示为-8,不再表示-0。最后,4位二进制补码表示范围为-8到+7,n位二进制补码表示范围为-2(n-1)到2(n-1)-1。
  当然求补码的最简单的方法还是“求反加1”(真香)。
  乘法就是移位相加,除法就是移位相减,具体内容比较复杂,就不在这里介绍了。
  本小节只是简单介绍一下计算机的运算方法,更为详细的内容各位可以查看数电和微机的相关知识。

2.指令和语言

  计算机只能认识0和1,从上面的知识我们知道了数据怎么参与运算的,现在我们要解决怎么让计算机计算。
  听起来很奇怪,但确实如此,我们怎么让计算机把这两个数相加,怎么让它把结果放到哪个存储器中去,答案当然很粗暴,就是“告诉它”,当然直接说是不行的,它也听不懂。我们上面说了计算机只能认识0和1,所以我们的命令,即指令也要是用0和1表示,这种计算机能直接识别的二进制指令称为机器指令,机器指令的集合就是机器语言。例如我们想把某个数移到某个地方去,我们可以打一串01代码,这个代码是独特的,计算机取到这个代码就明白我们希望它做一个数据传输的操作,从而实现人机的交流。
  当然,这样的指令又臭又长,不方便记忆,于是人们把这些指令符号化,用特定的符号代替那一串01代码,如用MOV表示数据传输,用ADD表示两个数相加,在配上固定的语法格式,就形成了汇编语言。当然机器不能认识MOV,ADD这种符号的东西,所以汇编语言(低级语言)和以后的高级语言都需要一个翻译器,将符号化的东西变回01代码,这一过程成为汇编
  汇编语言仍是比较低级的语言,人们又不断的更新,补充,最后就产生了各种高级语言,其中就有我们的主角——C语言(终于点题了……)。

三、C语言基础上(从数据到程序)

  终于到了C语言的部分了,我会按块给大家讲解。

1. 数据

  这里说的数据已经不同于上面讲过的计算机中的数据存储方式和运算形式了,对高级语言来说,我们更关心它的整体性质。
  C语言中的数据有两种表现形式,分为常量和变量。
  常量就是不能改变的量,有一下几种:
  整形常量:如具体的数字:123,0,-99等
  实型常量,如12.3,55.6,0.35,-56.0(十进制小数形式),12.3e4,-5.3e2,-56.1e-3(指数形式,就是类似科学计数法,只不过对前面的数没啥要求)。
  字符常量:’a’ ’n’ ’,’ ‘6’(普通字符,表示一个字符,要用单引号括起来,其存储的形式一般是ASCII,注意一次只能括一个,’kl’是不行的)

  字符常量还有一种叫转义字符,用来表示不能显示的字符(空格是可以显示的,你可以看到光标后移了!)常用\开头,如‘\t’表示将光标跳到下一个tab位置,’\n’表示换行,’\a’表示提示音,’\’表示要输出一个\(\被用作开头了,如果只写一个’\’,会被认为是转义字符的开头)

注:\ddd的例子:\101表示八进制数101的ASCII字符,查ASCII的表可知是A,所以’\101’和’A’是一样的,同理\x41表示十六进制41的ASCII字符,也是A。

  字符串常量:如“aaa”,“156”,“*/-+”等,用双引号括起来,注意:“a”也是一个字符串常量,因为字符串常量会在结尾有一个隐藏的\0作为字符串的结尾,所以“a”实际上是“a\0”,而 ‘a‘是只有一个a在里面的。
  符号常量:用宏定义指令#define定义的常量,如 #define E 2.71828
我们将E这个符号名定义为一个数2.71828,这样后面用到E时,就会自动替代为2.71828。
注:习惯上符号常量全大写。

  变量就是可以改变的量,它们的值通常是随着程序的进行不断变化的。变量要先声明才能使用,变量声明的语法如下:
  int a;
  double b;
  int 代表这个变量的类型,a是这个变量的名称。
  变量的类型是什么,其实就是对变量分配存储单元的安排。变量不同于常量,它是要一直变化的,所以计算机中会开辟一个内存的区域给这个变量,变量一变化,就改变这个内存区域的值,从而使内存区域保持当前的变量的值,那么这个区域有多大,就是要看变量类型了,我们可以用sizeof这个函数来查看某个变量的大小,如用int定义的变量,sizeof(int)显示为4,说明计算机在内存中为它开了4byte的空间(1byte = 8bit,即8位),而double类型的大小位8byte,当然还有很多其他类型,他们的大小之间或许存在不同,当然有些还有更为重要的性质,将在下文介绍。
  变量的大小有什么重要的吗?早在前面我们就提到过,如果一个数超过了能表示的范围,会发生什么?结果当然是错的,会变成对应的补码(参考前面9+7的例子),这对运算来说一般是不允许的,当结果可能溢出时,我们就要用更大的类型来放它。如果全用最大的类型来声明变量,发生溢出的可能性当然大幅下降,但内存是有限的,在内存中每开辟一个区域,内存就少一块,全用最大的类型来声明变量这种方法显然对内存的消耗是很大的,尤其是对于C51单片机这种内存本来就每多少的,这样的结果就可能会导致内存溢出。所以变量的声明是还是要合适。


  变量名的起法当然也是有规矩的,并不是说想叫什么叫什么,名字一般叫做标识符,C语言规定,标识符只能由字母、数字、下划线3种组成(想起中文名的小伙伴可以歇息了),且第一个字符必须为字母或下划线,如_456,k456,KK,kk,_o_p_q_等都是可以的,但456,4h5就不行。注意:KK和kk是不同的变量,即标识符是区分大小写的!
  变量名取的时候一定要有意义,好的变量名是成功的一半,我这里只是举例子随便写的,变量名的命名方法主流的有驼峰命名法,帕斯卡命名法,大家可以去学习一下。
  下面对一些重点的变量类型进行介绍。
  int——整型,大小占4byte,其特点是只能表示整数,如果在一个整型变量中存放了一个小数如2.6,实际上这个变量的值是这个数向0取整的值(即2),小数部分被忽略了,而不是四舍五入,如果在一个整型变量中存放了一个小数为-2.6,向0取整则为-2。
  double——双精度浮点型,大小占8byte,整数小数都能表示。
  float——单精度浮点型,大小占4byte,整数小数都能表示。
  char——字符型,大小占1byte,以ASCII形式存储一个字符,如char a = ‘A’,在内存中实际上存储的是A的ASCII,即65,所以char也可以看成是更小的int,因为它们都是只能存整数。需要注意的是,对char变量赋值为负数合法的,如char a = -9,此时它就不表示一个字符,而是表示一个整数,其表示范围为-128到+127。
  其余类型将会在后续介绍。
  我们可以对变量类型加修饰词,从而适应更为丰富的情况。上面介绍的所有类型都可以加前缀unsigned,表示这个数不以负数形式存放,即使给它一个负数,如:
  unsigned char a = -1;
  虽然在存储单元中放的是-1的补码,即1111 1111B,但计算机把它看做一个无符号数,当作8421码处理,则实际上a的值为255。
  如果没有特殊声明,编译器都将默认为signed,即带符号数。
  上面介绍的类型除了char外,其余都可以加long或short修饰,一般来说,long可以使原来的大小加倍,如原来double占8byte,long double 则占16byte;short使原来的大小减半,如原来的int占4byte,short int则占2byte。
  可以在常量的末尾加专用字符,表明这个常量的类型,如1.26如果不加修饰,编译器将默认为double处理,但1.26f就是告诉编译器1.26是一个float类型的数,编译器就知道怎么处理了。同理,1.26L表示这是一个long double的数。
  我们可以先声明一个变量,在去赋值,如:
  int a;
  a = 10;
  我们也可以在声明的时候就赋值,如int a = 10;
  我们只能操作具体的某个对象,如a,但不能对某个类型操作,所以int = 10是非法的。
  如果只声明而不赋值,结果就是编译器只是在内存中某个地方开辟了一块空间,但这个地方原来的值并没有被擦除,就成为了这个变量的默认初始值,由于我们不能确定一个变量被开在内存的哪一块区域,所以变量的初始值是随机且未知的,所以声明变量的同时一定要赋初值。
  下面对变量进行进一步阐述。
  当我们写下int a = 10;发生了什么?
  我们声明了一个int类型,名字叫a的变量,并给了它初值10,由前面的知识,我们可以知道,编译器在内存中随机的开辟了一块大小是4byte的空间,并将这片空间原来的内容改为10,即0000 000AH(十六进制),同时给这块空间起了名字为a,a就代表了这片4byte的空间,我们对a操作,就是对这片空间进行操作,所以我们改变a的值,也就改变了这片区域的值,从而实现了“变量”的效果。

2.运算

  简单的加(+)减(-)乘(*)除(/),大家上过小学都知道是什么,就不多说了,介绍一下取余运算符%,A%B的结果就是用A除B的余数,需要注意的是,A和B都必须是整数。
  需要注意的是不同的数据类型之间的运算,同类型之间没有问题,结果也是同类型的,其中int类型的计算需要注意,由于int没有小数,所以其结果不一定正确,如两个int类型的数3和6,做6/3的除法,结果为2,用int表示没有问题,但如果是6/4,结果是1.5,由于int向0取整数,所以结果为1,就会产生错误。
  不同类型之间遵循隐式转换,默认向更大的类型转换,如一个int类型的数加一个double类型的数,int类型会自动转换为double,结果也为double,同理,long double类型的数和double类型的数预算,double也会先转换为long double,再运算。
  我们也可以使用强制显示转换,如float a = 1.56f,前面说过这是一个float类型的数,
  如果我们希望在运算中a以int类型进行运算,就可以在运算式中将a用(int)a替代,这样就强制将float转换为int,一般来说这样必然会带来精度损失,不过有时我们希望只取整数运算。显示转换只在当前这一句中生效,a的值实际上并没由被改变,还是float型,值为1.56f,只是在运算中它临时变为int型,值为1。
   我们都知道+5和-5是什么意思,一个正数一个负数嘛。同样的对一个变量a,+a和-a的意思大家也能猜出来了,+a就是a,-a表示a的相反数。如果a为负数,+a还是a,是负数,由+(-5)还是-5这个例子大家应该很好理解。
   C语言对这些基本运算有简化的写法,如果有这样一行代码:a = a+5;那它可以简化为a += 5;同样的减乘除取余都可以简化。如果=右侧是也是表达式,先计算右侧的值,如a*=b+c,那么先计算b+c,再将这个结果与a相乘赋给a。
   1.加加减减运算符(请允许我这么叫它们)
   首先我们引出单目运算符和双目运算符以及三目运算符。
  对于上面的+a,-a,大家发现这些运算只用一个操作数,即只要一个数就能运算,这种运算符成为单目运算符(+,-)。
   而对于加减乘除取余,需要两个操作数,叫双目运算符。
   对于三目运算符,那肯定是要三个数才能算的了,C语言种只有一个三目运算符,是?,将在后面介绍。
   加加减减运算符也是单目运算符,即只要一个数就能算,其格式是:
   a++,a–,++a,–a
   其中a必须是变量,++的结果是使原来a的值自加1,再返回给a,即a++和a = a+1等价,同理–的结果是使原来a的值自减1,再返回给a。说白了就使让变量a自己加1或者减1,通常在需要记录次数的时候用。
   重点来了,++a和a++有什么区别。
  先上结论:++a是先使a加1,再使用a的值;a++是先使用a的值,再使a加1。
  听起来很拗口,举例子就好啦。
  我们定义了一个变量j和i,并对他们幅了初值0。则:
  a.1j = i++;
  b.2j = ++i;
  j的值将不同,虽然最后i的值都加1了,但由于执行的循序不一样,导致j的值不同。在○1中,由于++在后面,所以先使用i的值,那么这里用i的值干什么了呢?将i的值赋给了j的值,因为先使用,i还没加1,所以j等于i原来的值,即为0;而对于○2,由于++在前面,要先使i加1,则i变为1,再使用i的值,将i的值赋给了j的值,所以j的值为1.减减的道理是一样的,–a是先使a减1,再使用a的值;a–是先使用a的值,再使a减1。
   这两个例子都是最直接最基础的,可能比较简单,但道理是明显的,由于加加减减运算符可以在一个语句中被多次、不同地方的使用,所以需要把握好这些基本概念。
   对于什么++(i++)+++i这种没个十年脑血栓写不出来的代码,但总是有人喜欢考的东西,我只能说各位多做题吧……
  2.比较运算符
  大于(>),小于(<),等于(==),注意等于是两个等号;大于等于(>=),小于等于(<=),不等于(!=)。这几种比较运算符有小学知识概念应该可以理解,这些运算符是有返回值的,即它们是有结果的,如5>6,这个结果明显是假的,则这个式子的值是0,如果用一个变量a = 5>6,则a的值变为0。同样的,6 == 6是成立的,则这个式子的值是1,如果用一个变量a = 6==6,则a的值变为1。
  3.逻辑运算符
  逻辑与(&&),逻辑或(||),逻辑非(!),逻辑运算符表示多个bool之间的组合,与就是“一假全假,全真才真”,或是“一真则真,全假才假”,非就是和原来的反着来。这些比较基础没啥可说的,大家自学也可以学习,就不多赘述了。
  应当指出特殊情况,如(5==6 && a++ != 7),这个逻辑与将两个逻辑式5 == 6和a++!=7结合起来,有前面的知识我们知道,只要有一个逻辑式为假,整个结果都是假的,实际上运行的时候一看,发现5 == 6已经是假的了,那这个逻辑式就一定为假,其结果为0,后面的a++!=7是否成立根本就不需要看,所以它就不看了,但大家发现什么不对劲的没有?a++!=7中包含了一个执行表达式(请允许我这么叫)a++,原本这个表达式是判断a是否等于7,再将a+1,现在不执行了,a+1这一步就没了,所以a的值就不变了!这一点在有些时候是致命的,如果a是一个循环次数的话,整个程序可能会产生死循环,需要注意这一点。同理逻辑或在前面为真的情况下也不会管后面的逻辑表达式了。
  4.三目运算符(?)
  三目运算符其实就是一个简单的比较和返回的组合,和条件分支(后文介绍)类似,其基本用法:
  条件?是:否
  如x>10?a=5:a++
  三目运算符对条件进行判断,如果为真(成立),就执行冒号之前的操作,如果为假,就执行冒号后面的操作。这里的操作可以是多样的,可以为赋值,也可以是其他的算术表达式。
  注意这是一个整体,?和:必须配对使用。
  5.优先级和结合性
  单目的优先级高于双目的高于三目的,括号优先级最高,赋值运算符最低,目前所学的优先级这样排列就可以了。
  对于同级运算符,算术运算符都是自左向右运算的,如a+b+c,先计算a+b,再计算加c的值,这种结合性又称为左结合性。赋值运算符(将下面介绍)具有右结合性,如a=b=c,是先将c的值给b,再将b的值给a。
  6.赋值运算符
  这里将赋值作为一种运算,即数据传输的操作。
  在编程中,=代表赋值运算符,它并不代表左右两边相等这一状态(数学中等号的概念),而是表示将=右边的值(右值)赋给=左边的值(左值)。赋值运算符的左值要是一个可以修改的值,如变量,不能修改还要赋给不同的值,这显然是不行的,算术表达式也不能做左值。右值的要求低了很多,凡是左值都可以做右值,这意味着赋值运算符可以“连等”,如a=b=b+c
  有上面的结合性可知,先将b+c的值给b,此时b是左值,再将b的值给a,此时b是右值。但a=b*c=b+c是非法的,因为b*c对右侧的=而言是左值,而它本身是算术表达式。

3.语法

  语句的概念很多,但很多只用了解就可以,这里重点介绍一下语句和表达式。
  语句一般是成对的,如if()else;或者是表达式后加分号的,如a+=5;一般来说后面有分号的是语句。
   表达式种类就很多了,前面的算术表达式都可以。
   如赋值语句a=3;它是由赋值表达式a=3加上后面的分号构成的。
   如a+=3;它是由算术表达式a+=3加上后面的分号构成的。
   如i++是表达式,它是算术表达式,加上分号后i++;才是语句。
   如x+y;也是语句,可以简单的认为它后面有分号,当然实际上它是一个算术表达式,它是结果是x+y的值,但这个值并没有保存到某个地方之中(如变量),所以这个表达式并没有产生实质性的作用,因为它的值在这个语句执行完后就不见了。
   空语句——只要一个分号,啥内容也没有。看起来很没有,其实有时候可以起到占位的作用。
   复合语句,用一对大括号{}括住的语句,是一个整体,可以看作复合语句,现在复合语句的作用貌似没有,之后它的作用将会大大体现。
  分号是语句的特征,表示一个语句的结束,是语句之间的分界。
  下面对赋值语句进行讲解。
  首先要说明的是,赋值表达式也是有值的,它不仅实现的赋值操作,它本身也有值,其值为赋的值的值,拗口?上例子。
  如a=6+(c=4)
  这是一个赋值表达式,当然它中间还有一些算术表达式。首先看括号的,将4赋给c,同时这个赋值表达式也有值,就是赋值的值,即为4,再加上6赋给a,所以a是10,当然赋给a这一步也是一个赋值表达式,所以上面这个赋值表达式最后也是有值的,值为赋给a的值,即为10,如果b=a=6+(c=4),那么b的值就变成了10。
  注意a=6+c=4是不对的,因为+的优先级高于=,所以会先计算6+c,而这个是算术表达式,却作为=4的左值,所以编译会报错。
  从上面我们也可以看出表达式可以嵌套表达式,这使得C语言的表达式可以变得相当复杂。
  需要说明的是,在定义变量是,我们可以
  int a=3,b=3,c=3;
  用这种方法定义多个同类型的变量,并给它们赋初值,如上面就定义了3个整型的变量,初值都为3。但 int a=b=c=3;是不行的。

#代码训练与详解

  OK,现在我们已经入门差不多快一半了。有了上面的基础,我们就可以写一些自己的代码了。(终于见代码了……)
  这里我使用的是Dev-C++ 5.11版本,在64位windows10环境下运行。用Dev-C++的原因首先是因为操作简单,不用建立项目,第二是因为当初我学C的时候就是用的这个,虽然现在用VS用的比较多,但VS写C事情很多,对初学者来说,能用、简洁才是最好的。
  好了,让我们开始敲代码的旅途吧。
  打开后是这样的:

  点开文件->新建->源代码

  之后会变成这样

  当然这个是我已经调教过了,不过左上角会显示一个未命名的栏这个是一样的。大家可以在工具->编译器选项中选择调教。

  这里可以改变字体和大小,也可以显示行号。
  现在,我们可以开始了。
  首先,先来个经典的Hello World。

#include<stdio.h>
int main()
{
	printf("Hello World");
	return 0;
}

  OK,差不多之后呢,我们先保存一下,ctrl+s,会弹出保存的框。

  这里大家可以选择保存的地方,注意保存类型在下拉中要选.c的。

  这样才是C语言的形式。
  点击保存,OK。
  接下来大家关注这几个

  圈住的从左到右依次是编译,运行,编译运行,全部重新编译,调试
  这些听不懂,没关系。还记得我们开头说过的,机器只认识0和1,而我们写的高级语言全是符号化的,所以我们需要一个翻译官,把我们写的翻译成机器看的懂的,这一过程就叫编译,对应上面最左边的按钮,编译是重要的,一方面是当翻译官,另一方面是编译器会在这一步帮我们查一下语法错误,比如语句的标志性分号少啦,算术表达式当左值啦什么的,很有用。翻译完了,我们希望计算机执行一下,就是运行。当然编译运行就是先编译,在运行。全部重新编译是针对多文件编程时候的,现在先不介绍。调试是所有程序员必备的,也是最头疼的,会在适当的时候为大家介绍。
现在,让我们编译运行一下这个源代码。

  它弹出一个这样的小窗,叫“小黑窗”(我一直都是这么叫的,不过问题不大……),上面写这我们希望的话Hello World,表示我们成功啦。
  现在让我们来看看原码
#include<stdio.h>
int main()
{
   printf(“Hello World”);
   return 0;
}
  大家会发现,这么多单词,最后只能看见一个Hello World,那么别的那些是干什么的呢?
  编程是有框架的,就像数学题先写个解,编程也是有固定格式的,大家现在可以认为其他部分是编程的固定格式,每次编程的时候把这个格式敲上就行了,当然我不会只满足于说这种大空话,水文章,下面我会尽量用不超纲的语言向大家描述这个原码的组成部分。
  首先,大家会看到打头的#include<stdio.h>,这是什么意思呢,其实这个不是每个都是必要的,比如下面的程序

  它也是可以运行的

  只是这次小黑窗和上次相比变空了,大家发现了什么不同吗?
  Hello World的程序里面有一个printf,后面这个没有。
  如果我们不写#include<stdio.h>

  编译器会报一个警告,说它不认识printf。
  看来#include<stdio.h>和printf关系很大啊,实际上#include<stdio.h>就是为了printf服务的,printf我前面都没有介绍过(当然会在下一节介绍),因为它不是C语言自带的,我们打一个int,C语言编译器知道这是一个整型变量的类型,是因为C语言的创造者就是这样规定的,而printf并不是官方规定的,所以C语言编译器不认得。
  我要怎么让它认识这个printf呢,实际上printf是定义在一堆文件中(头文件),你编译器不是不认得吗,我直接把说明书给你,说明书里告诉你printf是干啥的,怎么用的,这样我后面用printf的时候,编译器就知道了,这是说明书里的东西,就认得了。这个说明书就是头文件,把说明书给编译器的过程就是#include<stdio.h>这句的作用,叫做包含头文件。
  这个说明书的名字是stdio.h,其中.h表明这是个说明书,就像.mp4是视频的后缀一样。说明书里详细说明了printf的用法,当然一个说明书里还可能有别的东西的用法,这里先按下不表。
  OK,说完了第一行是干啥的,我们来看后面。
int main()
{
   printf(“Hello World”);
   return 0;
}

  大家首先会看到一个熟悉的int,后面有一个main(),这是啥?
  我这里写了2个差不多的东西

#include<stdio.h>
int tese()
{
	printf("NUM.2");
	return 0;
}
int main()
{
	printf("NUM.1");
	return 0;
}

  除了main变成了test,剩下的都没有本质区别,我们运行看看。

  它显示的是NUM.1,有Hello World的例子大家应该能猜到printf的作用,就是把“”中间的内容打印到小黑窗上,现在小黑窗上是NUM.1,说明程序只执行了在main里的东西,test里的东西没有执行,所以就没有显示NUM.2。
  看来区别在main和test,实际上,我们写的很多,但程序不是从头开始执行的,哪怕是第一行#include<stdio.h>,程序执行的时候也不是从这里执行的,而是统一从main里执行(注:里的意思是main()后面一对大括号{ }之间的算main的里).#include<stdio.h>作用上面说了,是告诉编译器printf干什么的,当我们编译的时候,编译器充当翻译官,他从哪里开始翻译呢,并不是从开头,而是从main里的第一句,这是他碰到了printf,他知道这个在stdio.h的说明书里见过,于是他去查看了说明书,知道printf是干什么的,他再将printf翻译成计算机懂了0和1代码,整体是这样的过程。test不在main中出现过,所以翻译官就不去翻译,因为他就没见到test(他只翻译main里的,外面不管)。
  OK,那么还有一个东西。return 0;是什么。
  大家现在可以粗略的认为这是翻译官翻译的结束标识符,当翻译官看到这个语句,他知道自己的活干完了。(当然这么解释是不对的,具体需要到函数的知识讲解之后才能解释这个点,这里只是让大家对程序有更为感性的认识。)

  好了,程序的框架我们已经搞定了,下面让我们看个例子
  例:计算圆的周长。
  首先,我们知道圆的周长C=Π*d,d为直径。
  我们希望对于不同的d,这个程序都能使用,这意味着d是可变的,可变的,想到了什么?对啦,变量,我们用一个变量来放d,d是变量,得出的C也是变量。Π是3.14159,这个数是不会改变的,是什么?常量。现在,我们可以开始编程了。
  框架部分当然要照写。

#include<stdio.h>
int main()
{
	double d = 5,C;
	C = 3.14159*d;
	printf("C = %lf",C);
	return 0;
}

  于是,我们写出了这样的程序。
  大家也许会发现,这个printf怎么变了,里面东西不一样了。人家是可以有多胞胎的啊,printf有很多种,都在说明书里,所以这个也可以用,至于怎么用,是下一节的事情,现在大家只要知道这语句可以把变量C的值打印在小黑窗上就OK了。
  这个程序中,我们计算的是直径d=5的周长,运行后结果为

  用计算器算一边结果是一样的,说明这个是正确的。
  如果我想算d=6,我只需要改double d = 6,C;就OK。
  当然,大家会发现这个程序需要每次改完,重新编译运行才行,好像d的值根本不需要,既然每次d的值都是写死的,那我直接带入不就行了?
  确实,现在是这样的,但当我们学了如何从键盘上读入数据之后(当然,也在下一节),我们就可以每次从键盘上输入不同的值,而不用更改源代码,这才是变量真正发挥作用的时候。

  再来一个例子。
  例:找出5个数之间的最大数
  我们先设5个数为1,100,520.1314,-1.1,-20
  这里有两个数是有小数的,所以我们可以都用double来定义。
  那怎么比较呢?
  虽然能一眼看出来,但这种简单的操作计算机往往做不到。计算机只能一个一个比较。
  能实现比较的操作——当然是三目运算符啦,我们这里用三目运算符,先假设一个个数最大,让它与第二个比较,如果第二个比较大,就将最大的数变为第二个,否则还是第一个数。以此类推,比4次就OK了。
  我们得到下面的代码

#include<stdio.h>
int main()
{
	double a=1,b=100,c=520.1314,d=-1.1,e=-20;
	double max = a;  //最大的数
	max>b?:(max= b);
	max>c?:(max = c);
	max>d?:(max = d);
	max>e?:(max = e);	
	printf("%lf",max);
}

  这里:前面没有,代表着如果条件为真,就不操作。
  注意:这里的括号是必要的,因为赋值操作的优先级最低,如果max>b?:max= b;编译器会先运算max>b?:max这个三目运算符,但这个是算术表达式,作为了=b的左值,所以会报错。

补充:注释的方法
  注释就是给人看但不给编译器看的东西,编译器在翻译的时候不管注释,注释对于别人还有自己看自己的代码都很有帮助,自己不写注释过几天自己都不知道写的是什么,所以要养成写注释的好习惯。C语言注释的写法有两种
  1.// 双斜线后面的这一行的所有内容都是注释,如上面的例子。
  2./* */ 用这种符号括起来的东西是注释,如/* 这是注释!*/
  第二种注释可以跨很多行,只要配对就行

  被注释的字体颜色会发生变化,大家可以清楚的看出注释是否成功。

  好了,这一讲真是讲了不少东西。大家消化可能也需要一阵了,当然笔者也不是大佬,自然会有疏忽遗漏的地方,但笔者是想用自己的方式,向更多想学习C语言的人介绍和入门这门语言,欢迎各位读者指正。

  我们下一讲再见!