(一)零基础入门C语言 --- C语言之入门课程

一.C语言的程序结构

        任何一门语言都有其自己的程序结构,我们以最简单、最常用的代码来讲C语言的程序结构,Hello World!

#include <stdio.h>

int main(void)
{
    /*我的第一个C语言程序*/
    printf("Hello World!");

    return 0;
}

以上代码就是C语言的基本程序结构,以上代码运行出来,得到的结果如下图所示

让我们来分析程序结构

第一行 #include <stdio.h> 这一句话表示的是导入头文件内容,表明这个文件之后的代码会包含其文件的内容,如: 文件内声明的宏、函数、变量、以及其他各种各样的声明。以.h文件为后缀的文件我们称之为头文件(header file),头文件可用于声明.c文件内的函数,变量等内容。注意: 头文件内不允许编写逻辑代码,否则会报错。只有.c文件内才能够编写逻辑代码,切记!

第二行 int main(void)是一种典型的函数定义方法(后面会讲到),这里定义了一个名字称为main的函数,这个函数的参数为void,即为空参数,返回值为int类型的数据。这个函数我愿称之为C语言的心脏,因为它是整个C语言程序的启动函数,程序所有代码,都从这个函数的第一行开始运行, 一直运行到程序末端。

第三行/*我的第一个C语言程序*/ 这一句话在C语言中称为注释,何为注释?注释就是用于向读者说明一些注意事项,注释是不会被程序所运行的,程序会直接忽略这句话继续向下运行。那为什么要注释?当然是写给人看,可以是写给他人看,也可以是写给自己看,当你很多年后翻你以前写过的程序,有注释可以更快的理解这段程序的作用,不必要将整个代码再次去看一遍,节约开发时间。如果其他人需要你的代码,别人也能很快的知道,你写的文件是做什么用的,别人也能很快的上手使用你的文件,大大节省开发时间成本。

第四行 return 0; 这一句话是返回语句,表明执行到这句话后,程序即将退出这个函数,并且在退出后返回一个0出来。

通过这样一个程序结构,我们就在控制台输出了一句话,是不是很简单呢?我们来接着来看

二.C语言的基本语法

        1.对于每一条C语言的程序,在语句末尾,必须添加一个分号(注意: 是英文输入法的分号,不是中文输入法的分号)

        2.C语言的注释有两种方式,分别是单行注释和多行注释

单行注释: 在你需要注释文本的前面,写上//

例如:

//这是一条很有意义的注释内容,ababababababab..........

多行注释: 在你需要注释的文本前后分别添加/*和*/,注释内容在中间

例如:

/*   这
     是
     一
     条
     注
     释
*/

        3.标识符

        标识符是用来表示变量、函数、或其他自定义项目的名称,简单理解就是名字,定义标识符就是定义各种东西的名字。

        标识符命名具有一定规则:除了关键字不能用作标识符外,标识符必须要以a-z或者A-Z或者下划线_开头,后面可以紧接字母,数字,下划线。其他字符一律不能用作标识符。

        4.C语言的空格

        C程序运行过程中,程序会自动忽略空格,因此,我们可以利用空格,对我们的程序进行排版,让我们的程序具有更高的可读性,节约开发时间。

        5.关键字

        关键字是C语言中已经定义好的名字,每一个关键字都具有明确的意义,因此不能用作标识符,C语言中具有的关键字可参考C 基本语法 | 菜鸟教程 (runoob.com)

三.C语言数据类型       

        任何一门编程语言都少不了数据类型,了解数据类型并且牢记编程语言内的基本数据类型是极为重要的,在C语言中有着丰富的基本算术数据类型,还有可供编程人员自定义的数据类型,结构体(struct),共用体(union),枚举类型(enum)等。我们有必要去了解C语言中的所有数据类型,并且将其牢记在心中,在以后需要用到某种数据类型时,能够灵活运用类型。当然由此,引出了另一门课程,"数据结构与算法的设计"。

        让我们来看一看C语言中的基本算术数据类型

数据类型存储大小值范围                                  
char1字节-128~127
unsigned char1字节0~255
short2字节-32768~32767
unsigned short2字节0~65535
int2或4字节-32768~32767或-2,147,483,648~2,147,483,647

unsigned int

2或4字节0~65535或0~4,294,967,295
long4字节-2,147,483,648~2,147,483,647
unsigned long4字节0~4,294,967,295
float4字节1.2E-38~3.4E+38
double8字节2.3E-308~1.7E+308
long double16字节3.4E-4932~1.1E+4932

        上表列出了C语言中各种算术类型,每一种数据占用的内存大小是不一样的,在我们编程的时候,需要注意数据的范围,我们使用的数据绝对不能超过其最大表示范围,否则在程序运行中会遇到不可预料的结果,新手在编程的时候,总是会不注意数据溢出的问题,导致程序甚至整个系统出现不可逆转的问题。

         那为什么不同的数据类型,占用的内存有多种呢?比如说,int类型,可能是占用2字节,或者占用4字节,其实C语言内各种数据类型占用的字节数并不是确定的,因为C语言和操作系统挂钩,这个数据类型的大小取决于我们当前使用的编译器及其系统。那我们怎么具体知道,每一种数据类型占用多少字节?

        在这里我们介绍一个关键字sizeof,有些人说它是函数,因为它的使用方法和函数的用法一样,但实际上,它是一个关键字,并不是一个函数,是C语言内置的。

        它的使用方法很简单,如下列代码段所示:

//内存占用大小示例
sizeof(char)
sizeof(unsigned char)
sizeof(int)
sizeof(unsigned int)
sizeof(long)
sizeof(unsigned long)
sizeof(float)
sizeof(double)

        我们在执行这些语句时,它会返回一个值,这个值就是这种数据类型占用字节的大小,当然,sizeof的作用不限于计算内置数据类型的大小,还可以计算自定义数据类型的大小。

        下列为计算我们自定义数据类型占用字节大小的代码

typedef struct
{
    unsigned char x;
    unsigned char y;
    unsigned short length;
    unsigned short height;
    unsigned short girth;
    unsigned short area;
} Rectangle;

sizeof(Rectangle)

        我们自定义了一个结构体类型Rectangle,代表这个结构体代表的数据类型是矩形,这个矩形有几个属性

        x:矩形中心的横轴坐标

        y: 矩形中心的纵轴坐标

        length:矩形的长

        height:矩形的宽

        girth:矩形的周长

        area:矩形的面积

        这个Rectangle类型就是我们自定义的数据类型,我们仍然可以使用sizeof关键字来计算数据类型占用的字节大小,使用sizeof(Rectangle)即可计算其占用的字节数。

        表中有两种不同的数据类型,一种是整数类型,另一种是浮点类型,也就是小数类型,我们来思考一个问题,为什么long和float占用的字节数是一样的,但是为什么表示的数据的范围却有这么大的差别呢?让我们接着来看

        对于long及其相关的类型,这些属于整数类型,整数类型的表示方法如下图所示。下表表示的是数字10的二进制表示

                             第四字节           第三字节           第二字节          第一字节

                       |0|0|0|0|0|0|0|0|  |0|0|0|0|0|0|0|0| |0|0|0|0|0|0|0|0| |0|0|0|0|1|0|1|0|

如果表示的是-10呢?

                           第四字节           第三字节           第二字节          第一字节

                      |1|0|0|0|0|0|0|0|  |0|0|0|0|0|0|0|0| |0|0|0|0|0|0|0|0| |0|0|0|0|1|0|1|0|

对于有符号整数,我们使用最高位表示其为正数还是负数

最高位为1,代表这个数为负数;最高位为0,代表这个数为正数

        对于float类似的浮点类型数据,其数据表示方法同样用二进制表示,但是每个二进制位表示的意义不一样,让我们来看占用四字节的float类型的表示方法,我们来表示 -1.25这个数字

                             第四字节           第三字节           第二字节          第一字节

               |1|    |0|0|0|0|0|0|0|0|   |0|0|0|0|0|0|0| |0|0|0|0|0|0|0|0| |0|0|0|0|0|0|0|0|        

               31    30-------------23    22-------------------------------------------------------0

最高位:表示的仍然是符号,1为负数,0为正数

30~23位:一共八个位,表示指数部分

22~0位:一共23位,表示的是尾数部分

        这就是为什么,占用同样的内存,整数和小数表示的范围不一样,就是因为二进制中各位的意义不一样。这就说明,我们用浮点数完全代替整数吗?以后我全部都使用浮点数不就好了,不用再去考虑内存溢出的问题。可能大多数刚学习C语言的同学会有这种想法,但是结果可想而知,肯定是不行的,那C语言就没必要设置一个基本整数类型了。

        这个问题与我们当前的硬件有关系,对于硬件来说,整数的加法更加容易实现,使用的指令周期少,运行时间短,能够提高程序的运行效率;而对于浮点数计算,相对来说步骤较多,对于没有浮点计算单元的设备来说,计算浮点数,需要使用较多的指令,消耗的指令周期时间长,运行效率低,所以在我们的嵌入式开发中,为了提高程序效率,能不使用浮点数,尽量不去使用浮点数,除非万不得已,使用整数计算更加高效。

        除了基本的算术数据类型,C语言中还有其他的数据类型,比如void类型(空类型)、枚举类型、派生类型(指针类型,数组类型,结构体类型,共用体类型,函数类型等等)

        下面我们来讲一下void类型

        void类型表示的是空,主要用在三个方面        

        一、函数的参数为void

        二、函数的返回值为void

        三、指针指向的类型为void

        对于其他类型,指针类型,数组类型,结构体类型,共用体类型,我们在后期讲到相关内容的时候,我们再进行详细讲述。

四、C语言中的变量和常量

        在讲述变量之前,首先需要讲一个东西,数据在计算机中是如何存储的?或者说数据如何在各种智能设备中存储?

        在我们日常用的电脑中,大家都熟悉两个东西,一个是硬盘,一个是内存条,这两者是电脑运行不可或缺的东西,硬盘用于存储数据,在掉电的时候,硬盘能够将数据保存。内存条同样也是用于存储数据,但是只在电脑运行的时候进行数据存储和数据交换,断电后,内存条中的数据全部都丢失了。

        无论是硬盘和内存条,其内部都是由一个个半导体工艺器件构成,一个半导体器件可以存储8位数据,也就是8个二进制数据。由于大量的数据存储,一个硬盘或者内存条中,可能有成千上万个半导体器件,为了方便有序的使用这些半导体进行数据存储,我们给每一个半导体器件进行排序编号,每一个半导体器件都有一个编号,这个编号就叫做地址。计算机中每一个地址对应的都是一个存储八位数据的半导体器件,也就是说,每一个半导体器件都有一个物理地址与其对应。我们利用地址,就可以使用内部的半导体器件,从而进行数据存储或者数据读取。

        每个内存条或者硬盘都有对应的地址,其中有一个重要的就是基地址,基地址是指第一个存储器单元(我们后面统一说成存储器单元)所在的地址,后面存储器单元地址都是逐渐递增,如下图所示:

 

                        ​​​​​​​        

        这里存储器的基地址为0000H,后面存储器的地址逐渐递增,我们要操作第一个存储器单元,可以直接通过地址进行操作,这一部分我们放在后面的指针内容中进行讲解。我们只要知道器件的基地址,再知道器件的存储器大小,我们就可以通过地址来访问所有的存储器单元。这也是为什么C语言适合做底层硬件应用的原因,因为C语言可以直接操作器件的物理地址,从而方便的对硬件进行操作。好了,现在知道了,存储器是如何存储数据的,让我们再来讲C语言中的变量和常量。

1.C语言变量

        变量,顾名思义,可以变化的量,实际上只是定义某个或者某几个存储器单元的名称而已。C语言具有丰富的数据类型,每一种类型占用的空间不一样,所以在定义变量的时候,我们要指定变量的数据类型,让我们来学习一下如何定义,并且使用变量,变量一定要先定义,后使用!

int a;
int b;
unsigned char c;
float d;

        如上图,我们定义了两个整形变量int 名字分别为a和b,又定义了一个无符号字符变量,名字为c,又定义了一个浮点类型变量,名字为d,在定义变量的时候,系统就自动为这个变量指定一个存放地址。这也是为什么变量一定要先定义后使用的原因,如果你没有定义变量,那么你使用的变量就没有地址,自然就没有存放数据的地方,程序当然会报错。

        变量可以在定义的时候就赋予其值,如下所示

unsigned char a = 0;
unsigned char b = 0xaa;

        在定义a的同时,我们赋予a的值为0;在定义b的同时,我们赋予b的值为0xaa,当然,定义变量的时候不给初值也是可以的,这些变量可能初始值会是0,或者又可能不是。不过,为了养成良好的编程习惯,在定义变量的时候,尽量去赋予其初值,除非你特别清楚,这个初值一定不会出现问题,你可以不进行这步操作。

        所谓变量,就是可以变化的量,在程序运行过程中,我们可以对你之前定义的变量随时进行改动。比如下列操作

int a = 0;
a = 100;
a = -100;
a = 200;

        当然,我们也可以将一个变量赋予另外一个变量,比如下列操作

int a = 1,b = 3;
a = b;

我们定义a的初值为1,b的初值为3;下一步我们又把b的值赋予了a,a现在的值为3

        我们如果想进行更复杂的操作,也可以将某个数学表达式赋予变量,如下列操作

int a = 0,b = 10;
a = b*10-b+200;

我们赋予a的值为200-b+b*10,其结果是290

2.C语言常量

        常量,顾名思义,常数量,也就是说,不可以改变的量,我们称之为常量。在程序的运行过程中,这个量一直保持不变,并且也不能改变。

        常量分为很多种类型

第一种: 整数常量

        整数常量可以用十进制、八进制、十六进制表示,我们用前缀表示进制数,0x为前缀表示十六进制,0为前缀表示为八进制,没有任何前缀则默认为十进制整数。另外,整数常量还可以带一个后缀U和L,U表示这是一个无符号整数(unsigned),L表示这是一个长整型(long),如果你定义的常量很大,尽量加L后缀,以免产生数值溢出问题。以下举几个栗子

0xAA    //十六进制
077     //八进制
200     //十进制
10000000UL    //十进制,数字很大,标明为长整型
0xAAAAAAAAL   //十六进制,数字很大,标明为长整型

第二种:浮点常量

        浮点常量由整数部分,小数点、小数部分和指数部分组成。可以使用小数形式或者指数形式表示浮点常量。以下举几个栗子

3.1415
31415E-5

第三种:字符常量

        字符常量用单引号进行标记,比如我要表示一个字符x,可以如下表示

char a;
a = 'x';

这里我定义了一个字符型变量a,然后给a赋值了一个x字符,现在a的值就是x字符

当然,这是一般的字符常量,还有特殊的转义序列,用于表示一些特殊符号,详情可以见C 常量 | 菜鸟教程 (runoob.com),让我们举一个转义序列的栗子

char a;
a = '\\';

这里我定义了一个字符型变量为a ,然后给a复制了一个\字符,现在a表示的就是\字符

第四种:字符串常量

        字符串常量,就是由一个个字符常量组成的一串字符,字符串用双引号标记",比如我要表示一个字符串为Hello World!,我可以这样表示

"Hello World!"

这样就代表这个是一个字符串常量,里面的内容是Hello World!

以上所述的是一些用直接方式来表达的常量

,在C语言中,我们还可以通过间接方式来表达常量

间接方式表达常量,有两种方法:

        第一种是使用#define 预定义器来定义常量

        第二种是使用const关键字定义常量

第一种:#define定义的常量

#define预定义器我们可以这样理解,就是用一个名字去替代另一个名字,如下面栗子所示:

#define THIS_IS_A 'A'
char a;
a = THIS_IS_A;

这里用#define定义了一个名字叫做THIS_IS_A,这个名字代表的是'A'字符

然后定义了一个字符变量a,我们把THIS_IS_A赋值给a,现在a的值就是'A'字符

实际上,我们完全可以这样理解,#define就是进行了一个简单的替换,上面的代码等价于

#define THIS_IS_A 'A'
char a;
a = 'A';

将THIS_IS_A直接换成’A‘

那有人问既然可以直接替换,为什么我们要使用#define呢,直接指明是什么量不就行了吗?

答:我们当然可以直接指明值,但是,在一些移植过程中,使用#define 来定义一些常量,可以方便我们程序的移植,可以从某一款系统上直接移植到另一款系统上,只需要更改一些#define定义常量的值就好了,越学到后面,就越能意识到#define的重要性。

好了,我们现在知道#define的用法了,我们来做一个小测试,请问,下列代码a的值是多少?

#define Number 2+3/2
unsigned int a;
a = 3*Number;

        有人会说,这个不是很简单嘛,答案是9。在这里,我只能说,恭喜你,答错了,为什么答错了?我们来细看,刚刚说了,#define预定义器只是简单的替换而已,那我们将它来替换回去,看看表达式具体是怎样的。如下所示

#define Number 2+3/2
unsigned int a;
a = 3*2+3/2;

现在是否清晰明了呢?答案是7,并不是9。所以我们在定义数学表达式的时候,建议最好增加一个括号,来表示整个数学表达式,如果按下列定义,那答案就是9

#define Number (2+3/2)
unsigned int a;
a = 3*Number 

好了,使用#define预定义器来定义常量讲完了,我们来讲关键字const常量

第二种:const常量

        在C语言中,const是一个关键字,它的意义就是表示当前定义的东西是一个常量,无法改变。在使用const关键字来定义常量的时候,必须在定义这个量时就赋予初值,不能在定义之后再赋予值,这样在C语言中是不允许的!下面举一个栗子

const int a = 1;

这里定义了一个整形的常量a,它代表的数字是1。下列做法是不允许的!

const int a;
a = 1;

那这两种都是定义一个常量,那两种方法有什么区别呢?

        作者有点懒,别人的讲解都很到位,可以去看看他们的讲解,然后再自己去体会这两种定义常量的不同之处。

五、C语言中的运算符

        C语言中具有丰富的运算符,灵活的运用运算符,可以降低我们的开发时间。运算符具体详解,请看​​​​​​​C 运算符 | 菜鸟教程 (runoob.com),本人在此不过多赘述。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值