Please enable JavaScript.
Coggle requires JavaScript to display documents.
The C program Language (语句 (跳转语句 (goto语句, continue语句, break语句, return语句),…
The C program Language
基本结构
文件包含
头文件
#include<stdio.h>
标准输入/输出头文件
#include<math.h>
平方根函数sqrt
\(\sqrt{x}\)表示为x = sqrt(x);
两种常见形式
#include "文件名"
首先在源文件所在目录检索指定的文件,如果没有找到,则按系统规定的标准方式去检索文件目录,直至找到文件为止
#include <文件名>
只按系统规定的标准方式检索文件目录,直至找到文件为止
基本组成单位
函数
main函数
程序执行必备
程序执行开始
{\( \cdots \)}
函数体
可读性好坏
#增强可读性
书写规范
注释
多行注释
\(/* \cdots */\)
单行注释
//\( \cdots\)
一行内只写一条语句
正反大括号各占一行
每对大括号上下对齐
常量写在相等类运算符左边
#
0 == x
C书写格式自由
一个语句可写在多行
支持整个函数写在一行,即一行多个语句(但可读性非常差)
语句
每条语句的最后必须有一个
分号
C语言不包含输入/输入语句,而是调用标准输入/输出库中的函数scanf,printf完成
#stdio.h函数库
执行过程
1.编辑
2.编译
3.连接
4.执行
多个.obj文件以及库函数连接生成可执行文件
形成.obj文件
形成.c文件
标记、类型与表达式
标记
标识符
用途
对象
函数
标记或成员
结构体的
共同体的
枚举的
typeof名
宏名、宏参数
组成
小写字母、大写字母、
数字
、下划线_、通用字符名(\u031w)、实现定义的字符、$
\(\color\red{数字不能作为开头}\)
大小写敏感
常量
整数常量
只包括0、正整数、不包括负整数
不同进制的整数常量之间可直接运算
014+12+0xc
浮点常量
小数表示法
0.
.0
1.25
1.
指数表示法
0.000035 = 3.5e-5
枚举常量
类型int
字符常量
整数字符常量
由一对单引号括起来的一个或多个字符,类型int
一个字符:ASCII码值(即一个整数)
printf("%d,%d\n",'0','1'+3); \[\] //输出48,52
常用ASCII码
数字字符0~9
48~57
大写字母A~Z
#大写字母比小写字母小32
65~90
小写字母a~z
97~122
转义字符:由多个字符组成,但合起来仍然只表示一个字符
' ' (空格符)
大小
4byte
宽字符常量
串字面量
字符串字面量
结构与组成
翻译阶段'\0'被加到末尾
一对双引号" "括起来的0个或多个字符
存储方式
以char[]数组存储在内存中
细分
是否包含'\0'
包含
字符串字面量
如:"ab\0c"是字符串字面量,而不是字符串
若包含'\0',则实际上该数据只是具有表面上的形式,
字面
对应
实际
,实际上并不会输出,因为到\0节停止了,后面的不会作为字符串输出
不包含
字符串
如:"abc"既是字符串字面量也是字符串
不包含'\0',即意味着字符串字面量上的所有字符都会成为字符串输出,并不会提前终止
大小
字符数为n的字符串,占据n+1个字节 :!:
'hello
\n
'6个字符数,7个字节
UTF-8字面量
宽串字面量
标点符号
关键字
44个
变量与常用类型说明符
变量
声明方法
int area,length,high;
常用类型
int类型
大小
和CPU一次性能处理的位有关
16bit
2byte
32bit
4byte
实数浮点类型
float类型
大小
4byte
精度
6位
double类型
大小
8byte
精度
15位
char类型
大小
1byte
注意和'A'区分,'A'是字符常量,4个byte。
一片可变内容的内存空间,其值是该空间的内容,其名为变量名
作用域
局部变量
#
函数内声明的变量
作用范围:
只在本函数内有效
局部变量与全局变量同名,则在局部变量作用的范围内屏蔽全局变量
存储类别:auto/static(默认auto)
全局变量
#
作用范围:
从声明变量的位置到本源文件的末尾
作用
为函数之间数据传输构建了渠道
存储类别:extern/static(默认extern)
存储类别
auto
static
register
局部变量的值可存储在寄存器中,以提高执行效率
extern
typedef
_Thread_local
生存期
静态存储变量
指程序运行期间分配固定的存储空间的方式
静态局部变量
在程序整个运行期间都不释放
在编译时赋初值,即只赋初值一次
在没有初始化的情况下,静态局部变量的值是0
static int c = 3;
动态存储变量
根据需要进行动态的分配空间的方式
数据种类
函数调用时的现场保护和返回地址等
局部变量
int n;\(\ \ \ \ //等价于auto \ \ int\ \ n;\)
函数调用开始,分配存储单元;函数调用结束,存储单元被释放
每调用一次函数都重新赋初值一次
在没有初始化的情况下,自动变量的值是不确定的。
形式参数
表达式
运算符
按操作对象个数分类
双目运算符
赋值运算符
简单赋值运算符
表达式:\( b = 9\)
复合赋值运算符
*= 、/= 、%= 、+= 、-=
先计算运算符右边的值
r * = 2+3
1 more item...
逗号运算符
表达式:5,3.6//结果为右运算对象的值3.6
乘法类运算符
%
两个运算对象必须是整数类型
:!:
其符号与第一个运算对象相同
:!:
\(8\%-3=2\)
\(-8\%3=-2\)
*
/
\(5/2=2\)
\(8/-3=-2\)
\(5.0/2.0=2.5\)
加法运算符
\(-\)
\(+\)
表达式
:\(9 - 5\)
关系运算符
>
<
>=
<=
表达式类型是int,表达式的值为1或0,。
相等类运算符
!=
==
结合性:从左到右
逻辑与运算符&&
逻辑或运算符||
单目运算符
一元加、一元减
\( 表达式:+5\)
\( 表达式:-5\)
整数提升
\(sizeof +ch\)//大小为4
\(sizeof ch \)//大小为1
#整数提升
\(表达式:+1.5\)
后缀增1、后缀减1运算符
先赋值,再自加或自减
前缀增1、前缀减1运算符
先自加或自减,再赋值
++E等价于E+=1
类型转换运算符
表达式:(int)d %3
sizeof运算符
\(sizeof 2 + 3\)
sizeof优先级高于+,先结合2,故结果为7
逻辑非运算符!
若运算对象为数值
如果运算对象的值等于0,则表达式的值为1
表达式:!5的值是0
如果运算对象的值不等于0,则表达式的值为0
若运算对象为字符,则其值为ASCII码值
表达式!'A'的值是0
表达式!NULL的值是1
三目运算符
运算对象1?运算对象2:运算对象3
表达式的类型
运算对象2和运算对象3进行常用算术转换后的结果类型
运算符的算术转换
运算符的优先级
!>算术运算符 > 关系运算符 > 相等类运算符>逻辑运算符(&&>||) > 条件运算符>赋值运算符。逻辑运算符中“逻辑非 !”除外。
运算对象
三种基本结构
循环
选择
顺序
语句
复合语句
{\( \cdots \)}
不需要分号;
选择语句
if语句
形式
\[if(表达式)\\语句 \]
\[ \begin{align*}&if(表达式1)\\&\ \ \ \ \ 语句1\\&else\ \\&\ \ \ \ \ 语句2\end{align*}\]
\[ \begin{align*}&if(表达式1)\\&\ \ \ \ \ 语句1\\&else\ if(表达式2)\\&\ \ \ \ \ 语句2\end{align*}\]
else总与最近的if配对
switch语句
控制表达式只能是整数类型
执行完某个case后面的语句,并不会退出switch,而是一直执行直到switch语句结束
如果想立即退出switch,可使用break语句
default可以放在任何位置,功能相同
case后面只能是整数常量表达式
表达式语句
i++;//表达式+分号
;//空语句,表达式不执行任何操作
循环语句
for语句
一般形式
\[for(表达式1;表达式2;表达式3)\\语句\]
执行顺序
1.计算表达式1
2.计算表达式2
表达式2的值不等于0
执行循环体
计算表达式3
1 more item...
表达式2的值等于0
退出for语句
表达式1表达式2表达式3都可省略
while语句
do while语句
跳转语句
goto语句
continue语句
break语句
return语句
常用类型数据的输入和输出
printf函数
构成
格式控制字符串
普通字符
转义字符
\n
在输出时原样输出
printf("ABC");//控制台屏幕输出ABC
转换说明
%
[标志]
[最小输出宽度]
[.精度]
2 more items...
表示输出的最小位数,实际位数多余定义的宽度,按实际位数输出,若实际位数少于定义宽度,右对齐,在左边补充0或空格
+
输出正数时,在数字前面加上+号
空格
输出值为正,在数字前面加上空格,为负时冠以符号
-
左对齐,右边填空格
#
表达式1,表达式2,,,表达式n
scanf函数
构成
格式控制字符串
普通字符
输入时原样输入
scanf("x=%d,y=%d",&i,&j);//控制台键盘键入时(x=10,y=20)
转换说明
%
[*]
[输入数据宽度]
[长度修饰符]
1 more item...
scanf("%5d",&n);//实际键盘键入123456,只读取12345到变量n中,其余部分被截去
scanf("%3d%3d",&n,&m);//当输入123456,读取123到n,456到m
*是抑制符,读取的数据不会存储到相应的变量中,即跳过该输入值
变量1的地址,变量2的地址,,,变量n的地址
数组类型
一维数组
大小
声明数组时所声明的空间大小
赋值
从键盘读取
以int为例其他所有类型,循环scanf("%类型",&s[i]);
其中char类型支持sanf("%s",s);
1.只能在声明时为为数组赋值
2.其他位置只能为数组元素赋值
冒泡排序
n个数,总共需要n-1次循环排序,每完成一次排序,则就有一个元素被敲定,总排序元素减1,每一次循环排序的总元素个数都是减1,因为判断是s[j]>s[j+1];故第一次循环最大是j=n-1个,如果是n个则n+1超出循环,而每次递减,也就是n-i;(i是循环次数,第一次为1)
外层循环i=1;i<n;i++
内层循环j=0;j<n-i;j++
数组元素类型为char的数组可存储多个字符,如果最后一个字符是空字符'\0',则可将这多个字符理解为字符串
一维数组和指针变量
数组名a是指向a[0]的指针,且是不可修改的左值。
使指针指向数组元素
p=a
#等价
p=&a[0];
p+i等价于&a[0]+1*sizeof(int)
#等价于&a[i]
a+i;
下标运算符[ ]
一个运算对象的类型是指针类型
另一个运算对象的类型是整数类型
p[i]=*(p+i)
数组a中第i个元素的表示方法
a[i]
*(p+i)
p[i]
*(a+i)
数组a中第i个元素地址的表示方法
&p[i]
p+i
&a[i]
a+i
二维数组
形式
类型说明符 数组名 [行数][列数];
初始化
int[3][5]={1,2,3,4,5,6,9,8,1,2,3,4,5,6,9};
int[3][5]={{1,2,3,4,5},{6,9,8,1,2},{3,4,5,6,9}};
字符串
三种初始化方法
char s[5]={'b','l','u','e','\0'};
char s[5]={"blue"};
char s[5]="blue";
输出
\(printf("\%s", 数组元素为char类型且存储字符串的数组名) \)
char s[4]={'b','l','u','e'};不能用下面的方式输出,因为不以'\0'结尾不是字符串
输入
sanf("%s",数组元素类型为char的数组名);
遇到空格、tab、回车符停止读取,并将'\0'存储到最后一个字符的下一个数组元素中,空格,换行,回车被丢弃
常见字符串处理库函数
include<stdio.h>
gets();
puts();函数
include<string.h>
strcpy(数组元素为char的数组名,字符串);
复制字符串到第一个数组中,包括'\0'
strcmp(数组元素为char类型且存储字符串的数组名1,数组元素为char类型且存储字符串的数组名2)
strlen(字符串);
计算并返回字符串的长度,不包括'\0'
指针与字符串
通过指针变量访问字符串
"hello"并非一个值,而是字符数组{'h','e','l','l','o','\0'}
\[\begin{align*} &char \ p; \\&p\ ="hello"; \\&char *q="Chinese";\end{align*}\]
p="hello",即p={'h','e','l','l','o','\0'};
指针类型
指针和指针变量
访问内存中存储单元的方式
访问方式
按变量名存取变量值的方式
#
间接访问方式
将变量名的地址存储到另一个变量中,也就是存储到指针变量中
指针变量的声明
类型说明符 * 变量名1,[*变量名2,······]
变量名
类型说明符
指针变量只能存入由系统分配的地址
运算符
取地址运算符&
*&x相当x,&*x相当于p
间接寻址运算符*
*p等价于变量x
①声明指针变量的标志
②间接寻址运算符
③乘法运算符
前缀加前缀减,后缀加,后缀减优先级都比*高
*p++
对p赋值后,p=p+1;
*++p
p=p+1后,对p间接寻址,也就是*(p+1)
*(p++)
先运算p++,p++将值先赋给*,执行*p,等语句结束后再执行p++,也就是p=p+1;
*(++p)
先执行++p,即p=p+1;随后对改变后的p进行间接寻址
指针与二维数组
a[i][j]
a
值为&a[0]
整个二维数组的首地址
是二级地址
行首地址
a[i]
#
是i行行首的地址
一级地址
替换
*(a+i)
&a[i][0]
a+i
第i行第j列元素地址
a[i]+j
替换
*(a+i)+j
&a[i][j]
第i行第j列元素
a[i][j]
a[i]~*(a+i)
*(a+i)[j]
a[i]或a[j]都用p[i]~*(p+i)替换
*(*(a+i)+j)
a[j]~*(a+j)
*(a[i]+j)
利用指针访问二维数组
指向数组元素的指针
p=a[0]
a[0]==&a[0][0],即把第一个数组元素的地址给了指针p
p++;
行指针
类型说明符 \(\ \ \ \) (*指针变量名)[元素个数]
p=a(a是二维数组)
p指向数组a的0行,即p=&a[0];
p++;//p指向下一个行地址
*(*p+j) == * (a[i]+j)==*(a[i]+j)=a[i][j]
p是指针,*p指针的值,也就是a[0]指向的0行的行地址,*p+j就是a[0]这个0行首地址偏移j个int长度的行内下标为j的元素,*(*p+j)就是数组元素值
int (*p)[4];
意义
a pointer to an array of four int
指针数组
数组元素的类型是指针类型
int *p[3];
an array of three int *
函数
库函数
库函数由编译器提供,只需包含相应的头文件
如:abs、sqrt、scanf、printf
用户定义函数
①包含头文件
②1~n个函数声明
告诉main函数存在这么一个函数,main函数会去下面找,若函数定义出现在函数调用之前,
那么main函数就已经知道有这么一个函数,就不需要特地声明一下这个函数的存在了。
③main函数
完整形式
int main(int argc,char *argv[])
argc是指针数组argv的长度
④1~n个函数定义
形式
\(类型说明符\ \ 函数名(形式参数及其类型列表)\ \ 复合语句\)
函数体
复合语句
函数头
\(类型说明符\ \ 函数名(形式参数及其类型列表)\)
\(类型说明符:\ \ \ \ 函数的返回类型\)
不能是数组类型或者函数类型
返回类型是空类型,
可以没有
return语句,
也可以有多条
return语句,每条语句形式为\(\\return;\)
指向函数的指针变量
声明指向函数fun的指针变量一般形式
\(函数fun的返回类型\ \ \ \ (*指针变量名)(函数fun的形参及其类型列表)\)
赋值
指向一个具有相同形式参数类型,数量的函数
\( \begin{align*}&int\ \ \ \ max(int\ \ \ \ x,int\ \ \ \ y);\\&int (*p)(int\ \ \ \ max(int\ \ \ \ x,int\ \ \ \ y);\\ &p=max; \end{align*}\)
使用
\(c=(*p)(a,b)\)
递归
必须要有结束条件
自我调用
结构体变量与函数
宏定义
一般形式
#define 宏名 宏体
需要注意的问题
函数调用时,先求实参的值,然后将这个值赋给形参,而宏调用时,只是简单的用实参替换宏体中的形参。
\( \begin{align*} & \#define\ \ \ \ SUM(a,b)\ \ \ \ a*b \\&SUM(1+2,3+4)\\ &结果是1+2*3+4,值为11 \end{align*} \)
作用
一种简单的替换,不做任何运算,也不做任何错误检查
结构体、共同体、枚举类型
结构体
声明
\( \begin{align*}&struct\ \ [标记名称]\\ &\{ \\&\ \ \ \ 成员列表 \\ &\};\\&struct\ \ 标记名称 \ \ 变量名1[,变量名2,变量名3····] \end{align*}\)
\( \begin{align*}&struct\ \ student\\ &\{ \\&\ \ \ \ char\ \ sno[8];\\&\ \ \ \ char\ \ name[20];\\&\ \ \ \ char\ \ sex;\\&\ \ \ \ struct\ \ date\ \ birthday;\\&\ \ \ \ double\ \ score[3] \\ &\};\\&struct\ \ student\ t=\{"2015001","LiMing",'M',\{1997,11,18\},\{85.0,92.5,85.5\} \};\end{align*}\)
引用结构体类型的变量
结构体类型的变量名.成员名
\( \begin{align*} &s.age = 20;\\&s.age++; \\&sum=s.score[0]+score[1]+s.score[2];\end{align*}\)
如果成员本身又是一个结构体类型的变量
t.bithday.year
为结构体变量赋值
除了初始化以外,其他地方只能给结构体成员赋值,或者用同类型的结构体变量为其赋值。
指向结构体类型的指针变量
\(\begin{align*}&struct\ \ student *p,s;\\&s.sex='M';\\&s.age=18;\\&p=\&s;\\&printf ("\%s\%s\%s" ,s.sno,(*p).sno, p \rightarrow sno); \end{align*}\)
结构体类型与数组
单链表
库函数
malloc
分配长度为size个字节的存储单元,当执行成功时,返回一个指向所分配和释放存储单元;否则,返回NULL
malloc(int size);
free
free(*ptr);
释放指针变量ptr指向的存储单元
所需包含的头文件
stdlib.h
结构
数据域+指针域
\( \begin{align*}&struct\ \ \ \ student \\\ &\{ \\&\ \ \ \ char\ \ \ \ sno[8];\\&\ \ \ \ char\ name[20];\\&\ \ \ \ char\ sex;\\&\ \ \ \ int\ age;\\&\ \ \ \ double\ score;\\&\ \ \ \ struct\ \ student\ *next; \\ &\} \end{align*}\)
文件
打开文件
\(\begin{align*}&FILE\ \ *fp1;\\&fp1 = fopen("data.txt",r); \end{align*} \)
r
读
w
写
a
追加
关闭文件
\(filecloses(文件指针)\)
文件的读写操作
字符读写库函数
fputc(字符数据,文件指针);
ch=fgetc(文件指针);
字符串读写库函数
fputs(字符串,文件指针);
fgets("数组元素的类型为char的数组名",整数n,文件指针)
库函数
fprintf
fscanf
逻辑运算符