C语言概述
-
标准C库
ANSI C共包括15个头文件。
1995年,Normative Addendum 1(NA1)批准了3个头文件(iso646.h、wchar.h和wctype.h)增加到C标准函数库中。
C99标准增加6个头文件:
(complex.h、fenv.h、inttypes.h、stdbool.h、stdint.h和tgmath.h)。C11标准中又新增了5个头文件:
(stdalign.h、stdatomic.h、stdnoreturn.h、threads.h和uchar.h)。 -
至此, C标准函数库共有29个头文件:
C语言特点
- C语言简洁、紧凑、灵活。C语言的核心内容很少,只有32个关键字,9种控制语句;程序书写格式自由,压缩了一切不必要的成分。
- 表达方式简练、实用。C语言有一套强有力的运算符,达44种,可以构造出多种形式的表达式,用一个表达式就可以实现其它语言可能要用多条语句才能实现的功能。
- 具有丰富的数据类型。数据类型越多,数据的表达能力就越强。C语言具有现代语言的各种数据类型,如:字符型、整型、实型、数组、指针、结构体和共用体等。可以实现诸如链表、堆栈、队列、树等各种复杂的数据结构。其中指针使参数的传递简单、迅速,节省内存。
- 具有低级语言的特点。具有与汇编语言相近的功能和描述方法,如地址运算、二进制数位运算等,对硬件端口等资源直接操作,可充分使用计算机资源。因此,C语言既具有高级语言便于学习和掌握的特点,又具有机器语言或汇编语言对硬件的操作能力。所以,C语言既可以作为系统描述语言,又可以作为通用的程序设计语言。
- 是一种结构化语言,适合于大型程序的模块化设计。 C语言提供了编写结构化程序的基本控制语句,如if~else语句、switch语句、while语句、do~while语句等。C程序是函数的集合,函数是构成C程序的基本单位,每个函数具有独立的功能,函数之间通过参数传递数据。除了用户编写的函数外,不同的编译系统、操作系统都相伴还提供了大量的库函数供用户使用,如输入输出函数、数学函数、字符串处理函数等,灵活使用库函数可以简化程序的设计。
- 各种版本的编译系统都提供了预处理命令和预处理程序。 预处理扩展了C语言的功能,提高了程序的可移植性,为大型程序的调试提供了方便。
- 可移植性好。程序可以从一个环境不经改动或稍加改动就可移植到另一个完全不同的环境中运行。这是因为系统库函数和预处理程序将可能出现的与机器有关的因素与源程序隔开,这就容易在不同的C编译系统之间重新定义有关内容。
- 生成的目标代码质量高。由C源程序得到的目标代码的运行效率比用汇编语言写的也不过只低10%到20%,可充分发挥机器的效率。
- C语言语法限制不严,程序设计自由度大。 C程序在运行时不做诸如数组下标越界和变量类型兼容性等检查,而是由编程者自己保证程序的正确性。C语言几乎允许所有的数据类型的转换,字符型和整型可以自由混合使用,所有类型均可作逻辑型,可自己定义新的类型,还可以把某类型强制转换为指定的类型。实际上,这使编程者有了更大的自主性,能编写出灵活、优质的程序,同时也给初学者增加了一定的难度。所以,只有在熟练掌握C语言程序设计后,才能体会出其灵活的特性。
- 通过上述的介绍,已经了解了C语言的若干特点。C语言虽然是一种优秀的计算机程序设计语言,但也存在以下的一些缺点,了解这些缺点,才能够在实际使用中扬长避短。
- C程序的错误更隐蔽。C语言的灵活性使得用它编写程序时更容易出错,而且C语言的编译器不检查这样的错误。与汇编语言类似,需要程序运行是才能发现这些逻辑错误。C语言还会有一些隐患,需要程序员重视,比如将比较的"==“写成赋值”=",语法上没有错误,这样的逻辑错误不易发现,要找出来往往十分费时。
- C程序有时会难以理解。C语言语法成分相对简单,是一种小型语言。但是,其数据类型多,运算符丰富且结合性多样,使得对其理解有一定的难度。有关运算符和结合性,人们最常说的一句话是“先乘除,后加减,同级运算从左到右”,但是C语言远比这要复杂。发明C语言时,为了减少字符输入,C语言比较简明,同时也使得C语言可以写出常人几乎无法理解的程序。
- C程序有时会难以修改。考虑到程序规模的大型化或者说巨型化,现代编程语言通常会提供“类”和“包”之类的语言特性,这样的特性可以将程序分解成更加易于管理的模块。然而C语言缺少这样的特性,维护大型程序显得比较困难。 早期的计算机语言有BASIC语言、Fortran语言、ALGOL语言、COBOL语言和Pascal语言等,近来使用的人相对要少得多,除非是既有的软件系统使用这些语言,或者一些人想使用现成的程序或软件,才会使用这些语言。 现在的软件开发中更多地使用C++语言和Java语言,在开发Web应用软件时则会使用JSP语言和PHP语言等。随着面向对象技术的广泛普及,Java语言受到很多人的青睐,这是由于Java语言具有编程效率高,降低软件开发成本,不需要考虑存储的分配与回收等程序细节,编写出来的程序更具有健壮性,但是也一定程度上付出了运行效率的代价。C++语言则介于C语言和Java语言之间,也是面向对象的计算机语言,同时具有编程效率高和运行速度快的特点。 C语言是一种过程性的语言,职业的程序员或软件开发人员应该学习一下该计算机语言。这是因为,C语言可以代替机器语言或汇编语言编写运行速度快的程序;对于单片机应用、嵌入式系统和通信软件等是不可替代的;C语言的指针与计算机硬件的地址具有异曲同工之处,是了解计算本质的钥匙;通过C语言相关的存储分配函数,可以深入了解计算机存储分配的原理。
C语言发展史
K&R C
C89
C90
C99
C11
C18
C2x
第一章 初识C语言
- 源程序是人们作为字符序列创建出来的,不能直接执行,需要编译(翻译),将其变为可执行程序
- /* 和*/ 之间的部分是注释。注释可以有多行,用简洁的话来注释,方便阅读程序的人参考,包括自己,// 一样的作用。
注释是写给程序员看的,不是写给电脑看的。
C语言注释方法有两种:
多行注释: /* 注释内容 */
单行注释: //注释一行
- C语言主函数代码格式:
#includeABCtdio.h>
int main()
{
...........
return 0;
}
- 不要把stdio.h和studio.h 混淆
- 语句的末尾要加分号 “;”。
- 执行程序的时候{ 和 }之间的语句会按顺序执行。
- 换行符 \n
响铃符 \a
我们一般用反斜杠 \ 代替货币符号¥ - 字符串常量
“ABC”,这样用双引号括起来的一连串排列的文字,叫做字符串常量。 - int是整型
- 变量在生成的时候会被放入不确定的值。因此声明变量的时候,除了特别要求以外,一定要为其赋初始值,进行初始化。
- 初始化和赋值的区别
初始化:在生成变量的时候放入数值
赋值:在已生成的变量中放入数值
int abc = 123; //初始化
int xyz;
xyz = 57; //赋值
- 可以一次声明多个变量,要用逗号分隔变量名,例如:
int a,b;
- 格式化输出语句,也可以说是占位输出,是将各种类型的数据按照格式化后的类型及指定的位置从计算机上显示。
其格式为:printf(“输出格式符”,输出项);
printf("面积为%d。\a\n",width * height)
转换格式 %d 指定了读取十进制数
- 用于显示的函数有 printf 和 puts
- scanf 函数是读取通过键盘输入的数值并将其存储在变量中的函数。使用scanf 函数时,变量名前要加上 &。& 叫做取地址符
第二章 运算和数据类型
-
可以进行运算的符号叫做运算符。
根据运算对象——操作数的个数,运算符可以分为三类:
单目运算符,双目计算符,三目计算符 -
单目‘+’运算符的功能就是输出操作数本身的值,单目‘-’运算符的功能就是对运算符进行符号去反操作
-
将右操作数的值赋给左操作数的‘= ’,称为 (基本)赋值运算符
-
由变量和常量,以及连接他们的运算符所构成的就是表达式
-
在表达式后面加上分号‘;’,就形成了表达式语句。
-
数据类型实际上就是一个隐藏着各种属性的设计蓝图(可以看成做章鱼小丸子用的模具),包含某个类型的对象(变量),就是根据这个设计蓝图创建出来的实体,(相当于用模具做出来的章鱼小丸子)。
-
int
整数型,只能表示整数。即使被赋值给含有小数的值,小数部分也会被舍去。
像5和37这样的就是整数常量。 -
double
浮点型,只能表示浮点数(带有小数部分的实数值)。像3.14这样包含小数的常量,称为浮点型常量。 -
如果一个运算中有不同类型的操作数,就会进行 ‘隐式类型转换’。
运算对象——操作数的类型不同时,较小的数据类型的操作数就会转换为较大的数据类型,然后再进行运算。
因此,当一个运算中既有int类型又有double类型的时候,各操作数都会被转换成double类型。 -
若要将某个表达式的值转换为别的数据类型所对应的值的时候,需要使用类型转换符() 进行转换。
printf("平均值 = %f\n\n",(double) (a + b)/2);//这里的就是类型转化表达式
- 当用printf函数来显示double类型的值时,转换说明是 %f;当用scanf函数来读取时,转换说明是 %lf。
- 转换说明由0标志,最小字段宽度,精度,转换说明符构成。
- 若要在printf函数中显示%字符,需要在格式化字符中写入%%
基本数据类型的取值范围
1.比特位
- CPU能读懂的最小单位是:比特位,bit,b。每个比特位只能存放二进制数,即0和1.
2.字节
- 内存机构最小寻址单位:字节,Byte,B
注:1Byte = 8 bit
3.符号位
- 存放signed类型的存储单元中,左边第一位表示符号位。如果该位为0,表示该整数是一个正数;如果该位为1,表示该整数是一个负数。
- 一个32位的整型变量,除去左边第一位符号位,剩下表示值的只有31个比特位。
4.补码
- 正数的补码是该数的二进制形式。
- 负数的补码需要通过以下几步获得:
(1)先取得该数的绝对值的二进制形式
(2)再将第1步的值按位取反(除符号位)
(3)最后将第2步的值加1
5.取值范围
整数的类型
int
- 整型的使用
- 各种类型的存储大小与操作系统、 系统位数和编译器有关 ,目前通用的以64位系统为主。
- 在实际工作中, c程序通常运行在linux/unix 操作系统下.大众:使用windows10(64位)
- C语言的整型类型, 分为有符号 signed 和无符号 unsigned 两种, 默认是 signed
- C程序中整型常声明为int型, 除非不足以表示大数, 才使用long long
- bit(位): 计算机中的最小存储单位。 byte(字节):计算机中基本存储单元。
- 1byte = 8bit [二进制再详细说, 简单举例一个 short 3 和 int 3 ]
- short 3 在内存中占有 2字节
- int 3 在内存中占有 4个字节
浮点类型
-
浮点型使用细节
1.浮点型常量默认为double型 , 声明float型常量时, 须后加‘f’或‘F’。
2.浮点型常量有两种表示形式- 十进制数形式:如: 5.12 512.0f .512 (必须有小数点)
- 科学计数法形式:如: 5.12e2 、 5.12E-2
3.通常情况下,应该使用double型,因为它比float型更精确。
4.printf("d1=%f ", d1); // 在输出时,默认保留 小数点6位
字符类型
- 基本介绍
字符类型可以表示单个字符,字符类型是char, char是1个字节(可以存字母或者数字),多个字符称为字符串, 在C语言中 使用 char数组 表示,数组不是基本数据类型,而是构造类型。
字符类型使用细节
1.字符常量是用单引号(‘’)括起来的单个字符。 例如: char c1 =‘a’; char c3 = ‘9’;
2.C中还允许使用转义字符‘\’来将其后的字符转变为特殊字符型常量。例如: char c3 = ‘\n’; // '\n’表示换行符
3.在C中, char的本质是一个整数,在输出时,是ASCII码对应的字符。
4.可以直接给char赋一个整数,然后输出时,会按照对应的ASCII 字符输出 [97]
5.char类型是可以进行运算的,相当于一个整数,因为它都对应有Unicode码.
C语言变量的生命周期和作用域
C语言中常量
- C编程中的常量是一些固定的值,它在整个程序运行过程中无法被改变
字面常量
- 字面常量是直接写出的固定值,它包含C语言中可用的数据类型,可分为整型常量,字符常量等。如:9.9,“hello” 等就属于这一类常量。
const修饰的常变量
有的时候我们希望定义这么一种变量:值不能被修改,在整个作用域中都维持原值。为了满足用户需求,C语言标准提供了const关键字。在定义变量的同时,在变量名之前加上const修饰。
int main()
{
const a = 1;//const 修饰的常变量
return 0;
}
- const 修饰的常变量,本质上是变量。
- 但是具有常属性,所以不能更改。
define定义的标识符常量
- C语言提供了 ** #define ** 命令定义标识符常量,该标识符常量在程序中是个定值,通常用于代表数组容量或涉及数学的常量等。
#define PI 3.14159
#define SIZE 10 // 此处SIZE代表数组元素个数
int main()
{
int arr[SIZE]={
0};
return 0;
}
如需修改数组大小,只需将SIZE所代表的值修改即可,十分方便
枚举常量
- 日常生活中有一些代表实际意义的常量,有这么一个特点:数值较小且为非负整数。如一周有7天等。C语言提供了一种枚举(Enum)类型,能够列出所有可能会用到的取值,并给它们取一个名字。
int main()
{
enum Sex
{
//枚举常量 性别
MALE,
FEMALE,
SECRET
};
enum Sex s = FEMALE; //利用枚举常量给变量赋值
printf("%d\n", MALE);
printf("%d\n", FEMALE);
printf("%d\n",SECRET);
return 0;
}
-
在使用枚举常量的时候,需要注意以下几点:
- 不能对枚举常量赋值,只能将它们的值赋给其他的变量。
- 不能再定义与枚举常量名字相同的变量。
- 不能用 & 取得它们的地址。
第三章 运算符和表达式
赋值运算符
- 赋值运算符支持的是C语言的基本数据类型,包括int,char,double。字符串(字符数组)不能使用赋值运算符。
算术运算符
-
变量的自增或自减有两种写法:
变量名++; // 表示在本次使用变量后再自增;
++变量名; // 表示在本次使用变量前自增;
变量名 - -; // 表示在本次使用变量后再自增;
– - 变量名; // 表示在本次使用变量前自减;
关系运算符
- 注意
在C语言中‘=’表示赋值,而‘==’才表示判断,不能混淆。
逻辑运算符
逗号运算符
- 用法概述
C语言中","也是一种运算符,称为逗号运算符。其功能是将两个或多个表达式连接起来组成一个表达式。具体形式如下:
表达式1,表达式2,表达式3,…,表达式n
-
逗号表达式本身并不复杂,逗号表达式遵循一下三点特性:
1.逗号表达式从表达式1开始顺序从左向右执行;
2.其逗号表达式最后的值为最后一个表达式的值;
3.逗号运算的优先级最低,也就说明与其他运算符结合使用的时候,在没有括号的情况下逗号运算符最后才执行。
条件运算符
- 三目运算符也叫条件运算符、三元运算符,是由一个问号和一个冒号组成。
语法:
表达式1?表达式2:表达式3;
语义:
先执行表达式1,如果表达式1的结果如果为真,那么执行表达式2,并且这个整体的运算式的结果是表达式2的结果;如果表达式1的结果如果为假,执行表达式3,运算式的结果是表达式3的结果。
int a,b,c;
a=7;
b=6;
c=(a>b)?a:b;
等同于
if (a>b) c=a;
else c=b;
sizeof 运算符
语法
-
sizeof有三种语法形式:
1、sizeof(object); //sizeof(对象);
2、sizeof(type_name); //sizeof(类型);
3、sizeof object; //sizeof 对象;
-
基本数据类型的sizeof
等于各数据类型在内存中所占的字节数。这里的基本数据类型指的是short、int、long、float等简单的内置数据类型,由于它们和系统相关,所以取值在不同系统下可能会不同,可移植性较差。 -
指针变量的sizeof
等于计算机内部地址总线的宽度。所以在32位计算机中,一个指针变量的返回值必定是4(注意结果是以字节为单位)。- 指针变量的sizeof值与指着所指的对象没有任何关系。
-
数组的sizeof
数组的sizeof值等于数组所占用的内存字节数。 -
结构体的sizeof
sizeof的结果等于对象或者类型所占的内存字节数
第四章 语句和控制流
- 一个函数包含声明部分和执行部分。执行部分由语句组成,经编译后产生机器指令。声明部分不是语句,不产生机器指令。
语句和程序块
语句分类
C语言中的语句分为以下几类:
- (1).
控制语句:
条件语句:if(表达式) … else if(表达式) … else …
循环语句:
(1). for(表达式1; 表达式2; 表达式3) …。在C99标准中允许表达式1定义变量并赋予初值。推荐在这里给仅在循环中用到的变量定义,因为这样能缩短变量的作用域
(2). while(表达式) …
(3). do … while(表达式);(注意最后有分号)
多层循环嵌套时,一般长循环放在内层,短循环放在外层
跳过本次循环语句:continue
结束switch或循环语句:break
多分支选择语句:switch。
swich语句的模型
switch(整型数据(包括枚举型)或字符型数据) {
case 常量1: 语句1; break;
case 常量2: 语句2; break;
case 常量3:
case 常量4: 语句3; break;//此时常量3和常量4都进入到语句3
…
default: 语句n;(没有default时不符合则跳过)
}
函数返回语句:return
转向语句:goto。先在程序某处添加标记,如"mark: ",然后使用"goto mark;"跳转。
-
(2)函数调用语句
如printf(“Hello world.”); -
(3). 表达式语句
如赋值表达式a=3;,++i;等 -
(4). 空语句
直接只有一个分号的一行语句。 -
(5). 复合语句
用{}将语句和声明括起来的复合语句,也称语句块。
输入和输出语句
- C语言中常用语句是输入和输出语句 (scanf)(printf)
(1). printf
一般形式为printf(格式控制,输出表列)
- d格式符。用来输出有符号十进制整数。%5d表示数据占据5列且数据靠右,若想靠左则为%-5d。但%+d则表示输出整数前的正负号。长整型则为%ld,双长整型为%lld。l可放在d、o、x、u前。而在scanf中%5d则表示只读取前5位整数
- c格式符。用来输出一个字符
- s格式符。用来输出一个字符串。%5s在printf中表示只输出前5个字符,在scanf中表示只读取前5个字符.
- f格式符。用来输出实数.
(1). 基本型用%f。实数部分全部输出,小数部分输出6位
(2). 指定数据宽度和小数位数%m.nf。如果n为0则不会输出小数点。注意其中m是指包含小数点在内的整个浮点数长度而不单单指整数部分 - e格式符。用来输出指数形式实数。同样可以用%m.ne形式声明。也可用写成%E,此时输出指数中为大写E
- i 格式符。在 printf 中没有区别,在 scanf 时,%d 只与十进制形式的整数相匹配;而%i 则可以匹配八进制、十进制、十六进制表示的整数。 如输入的数字有前缀 0(018、025),%i会把它当作八进制数来处理,如果有前缀0x (0x54),它将以十六进制来处理
- o格式符。连同符号位一起以八进制整数形式输出
- x格式符。连同符号位一起以十六进制整数形式输出。%X时以大写形式输出
- u格式符。用来输出无符号整数
- g格式符。用来输出浮点数,并由系统自动选择为f格式或e格式输出。%G时以大写形式输出
- p格式符。用来输出地址
(2). scanf
一般形式为scanf(格式控制,地址表列)
其中,l可用于输入长整型数据如ld、lo、lx、lu以及double型数据lf、le。h可用于输入短整型数据如hd、ho、hx
在scanf(“a=%d, b=%d”, &a, &b);中输入则必须为a=1, b=2。若为scanf(“a=%d b=%d”, &a, &b);则a=1与b=2之间必须要有1个以上的空白字符
scanf和printf函数都有返回值,scanf返回正确读入了多少个变量,printf返回输出了包括换行符在内的有多少个字符。
(2)字符输入输出
- putchar( c )。用于输出字符变量c。若c为整数则当ASCII码处理
- c = getchar()。
用于输入一个字符,包括控制字符。
注意getchar函数返回的不是char类型而是int类型,
此时有可能出现潜在错误。一般用法为while((a = getchar() && a!=EOF) != ‘\n’) { }。EOF是指检测文件尾,在头文件中通过宏定义定义值为-1。键盘输入EOF其实是命令行环境遗留下来的,但是很多系统支持仿真的EOF,如用Ctrl+D(Linux系统)或Ctrl+Z(Windows系统)来模拟输入EOF。
判断语句(if,swich语句)
一、if(…) {…}
1.一般形式:
if (表达式) {语句;}
表达式:
1.用非 0 值表示真,用 0 表示假;
2.if(flag) 相当于 if(flag!=0);
3.浮点数无法与 0 比较,只能用近似的值比较;例: 1e-6 等于1x10的-6次方可以看成0来使用;
2.用于单分支选择结构;
3.如含有交叉关系,使用并列的if语句;
例:输出两个整数中的最大值
#include <stdio.h>
void main()
{
int a,b;
printf("请输入两个整数:");
scanf("%d %d",&a,&b);
if(a>b)
{
printf("max = %d\n",a);
}
if(a<b)
{
printf("max = %d\n",b);
}
}
二、if(…) {…} else {…}
例:输出两个整数中的最大值
//对非法字符进行检查和处理
#include <stdio.h>
void main()
{
int a,b,max,data;
printf("Input a,b:");
data = scanf(" %d,%d",&a,&b);/*记录scanf()的返回值;*/
if(data!=2)/*根据scanf()的返回值判断输入数据个数或者格式是否错误*/
{
printf<