重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
C语言知识点整理
创新互联公司专业为企业提供高碑店网站建设、高碑店做网站、高碑店网站设计、高碑店网站制作等企业网站建设、网页设计与制作、高碑店企业网站模板建站服务,十余年高碑店做网站经验,不只是建网站,更提供有价值的思路和整体网络服务。
一、 C语言简介
1、 特点
2、 历史:CPL>>BCPL>>B>>C>>C#
3、 关键字(保留字):类型说明(int等)、语句定义(if等)、储存说明(static等)、sizeof(长度运算符)
4、 标识符:用户自定义的各类对象(变量、函数等)的名称
规则:·由字母、下划线及数字组成,且必须由前二者开头
·不能与关键字或已定义函数同名
·大小写敏感(区分大小写)
·要求顾名知义
·不易混淆
5、 运行与调试
类型 |
关键字 |
字节数 |
表示范围 |
整型 |
short |
2 |
-~ |
int |
4 |
(-231~ 231-1) |
|
long int |
4 |
(-231~ 231-1) |
|
实型 |
float |
4 |
-3.4x10-38~ 3.4x1038 |
double |
8 |
-1.7x10-308~ 1.7x10308 |
|
long double |
8 |
-1.7x10-308~ 1.7x10308 |
|
字符类型 |
char |
1 |
-128~127 |
6、 注释(//以后的本行内容或/*与*/之间的内容)
二、 数据类型
1、 数据类型
拓:机器字长:CPU一次能处理数据的位数,通常与CPU的寄存器位数有关。
存储字长:存储器中一个存储单元(存储地址)所存储的二进制代码的位数,
指令字长:计算机指令字的位数。
数据字长:计算机数据存储所占用的位数。
存储字长取决于机器字长
指数形式是浮点数的一种表示方法;
指数形式,即科学计数法。其形式为:aEb;
代表a乘10的b次幂。 E也可以是小写,b必须为整数;
指数形式在输出的时候,可以指定浮点数输出为指数形式,格式为%e或%E,
区别为输出的指数形式浮点数E为小写或者大写;
如printf("%e", .0),会输出1.000000e+05。
2、 变量的定义
(不能int x1=x2=0; 但可以int x1,x2; x1=x2=0;)
·引用越界的数组数(如int x[10] = { 1,2,3,4 }; printf("%d", x[10]);)
编译时不报错,运行时出错,x[10]是一个随机数(即上一次栈遗留的数或者未初始化的数)
例:struct student {char name[10]; long number; float score;}
3、 变量的调用与范围
按作用域分:
生存期是从定义该变量的位置开始至源文件结束。
按存储方式分:
ü 静态局部变量:保存在全局数据区,而不是保存在栈中,每次的值保持到下一次调用,直到下次赋新值。 静态局部变量的用途有许多:可以使用它确定某函数是否被调用过。 C语言中静态变量只能被初始化一次,下次即使程序执行到初始化语句也会忽略
ü 静态全局变量:使得该变量成为定义该变量的源文件所独享。(非静态全局变量是如果在一个文件中使用extern关键字来声明另一个文件中存在的全局变量,那么这个文件可以使用这个数据。)
寄存器变量(register):存储在CPU中,容量小,速度快
4、 常量(#define)
5、 数据的输入
·\b:退格(8)
·\n:换行(10)
·\f:换页
·\r:回车
·\t:水平制表
·\v:垂直制表
·\’:单引号
·\”:双引号
·\?:问号
·\ \:反斜线\(92)
·\ddd:1至3位八进制数对应的字符(特别的,\0代表空字符,即终止符)
·\xhh:1至2位十六进制数对应的字符(如:\x41即\101,表示A)
·%的输出为’%%’
6、 数据类型的转换
三、 运算符与表达式
优先级 |
结合性 |
名称 |
符号或关键字 |
输入值(左) |
输入值(右) |
返回值 |
1 |
左 |
圆括号 |
() |
\ |
\ |
\ |
下标 |
[] |
\ |
\ |
\ |
||
2 |
右 |
逻辑非 |
! |
\ |
常量或表达式 |
!0=1;!(其他)=0 |
负号 |
- |
\ |
常量或表达式 |
相反数 |
||
自增/减(A) |
++ -- |
变量 |
\ |
|||
强制类型转换 |
(类型名) |
\ |
常量或表达式 |
规定类型对应数 |
||
间接引用 |
* |
\ |
地址 |
对应的值 |
||
取地址符 |
& |
\ |
变量或数组名 |
对应的地址 |
||
长度运算符 |
Sizeof |
\ |
类型名 |
类型长度 |
||
3 |
左 |
算术运算符(B) |
* / %(取余) |
常量或表达式 |
常量或表达式 |
数学运算值 |
+ - |
常量 或表达式 |
常量或表达式 |
数学运算值 |
|||
4 |
左 |
关系运算符 |
< <= > >= |
常量或表达式 |
常量或表达式 |
真即1,假即0 |
5 |
左 |
== != |
常量或表达式 |
常量或表达式 |
真即1,假即0 |
|
6 |
左 |
逻辑运算符(C) |
&&(逻辑与) |
常量或表达式 |
常量或表达式 |
一假则假,同真为真 |
7 |
左 |
||(逻辑或) |
常量或表达式 |
常量或表达式 |
一真则真,同假为假 |
|
8 |
右 |
条件运算符 |
(条件)?(选择1):(选择2) |
常量或表达式 |
常量或表达式 |
真取左,假取右 |
9 |
右 |
赋值运算符(D) |
= 及其扩展 (复合运算符) |
常量或表达式 |
常量或表达式 |
修改后的左值 |
10 |
左 |
逗号运算符 |
, |
常量或表达式 |
常量或表达式 |
最右边表达式的值 |
1、 常用运算符:
(计算时先进行高优先级计算,同优先级计算顺序由结合性决定)
A、变量在左则执行计算后自增/减,反之先自增/减后执行计算
B、取余要求两边均为整型,除号两侧均为整数则执行整除
C、自增自减整型实型变量皆可。
C、&&左为假则不执行右侧表达式,||左为真亦不执行右侧表达式
D、运算符=及其拓展要求左值可修改(不能是表达式、常量、数组名等),
=的拓展即为+=等,x+=b即为x=x+b
2、 表达式:变量、常量以及运算符的组合,按上述规律运算
拓:逗号表达式:从左往右一次执行语句,以逗号作为分界,最后返回最后一个语句的值
3、 表达式语句:在表达式后加分号构成语句
4、 表达式的真值:0为假,非零为真(!!-1=1)
5、 易错:表示a不等于0的关系是!a(×),是a(√)
6、 尤其注意‘=’和‘==’!它们的返回值不同
四、 常用函数及其头文件
头文件 |
名称 |
函数名 |
形参格式(a, b··) |
返回值格式 |
功能 |
返回值 |
|
stdio .h |
格式化输入 |
scanf |
char*等 |
int |
按格式输入 |
成功赋值的个数 |
|
格式化输出 |
printf |
char*等 |
int |
按格式输出 |
输出的字符数 |
||
单字符输入 |
getchar |
\ |
int |
输入单个字符 |
输入字符的ASCII |
||
单字符输出 |
putchar |
Char |
int |
输出单个字符 |
输出字符的ASCII |
||
字符串输入 |
gets |
char* |
char* |
输入字符串 |
输入的字符串 |
||
字符串输出 |
puts |
char* |
int |
输出字符串 |
是否成功输出 |
||
math .h |
取绝对值 |
(f)abs |
double/int |
double/int |
求a的绝对值 |
见左 |
|
取算数平方根 |
sqrt |
double |
double |
求a的算数平方根 |
见左 |
||
取n次方值 |
pow |
double, double |
double |
求a的b次方 |
见左 |
||
string .h |
字符串连接 |
strcat |
char*, char* |
char* |
连接并保存在前者 |
修改后的前形参 |
|
字符串复制 |
strcpy |
char*, char* |
char* |
将后者拷贝到前者 |
修改后的前形参 |
||
字符串比较 |
strcmp |
char*, char* |
int |
比较两字符串 |
异±1同0 |
||
字符串长度 |
strlen |
char* |
int |
求字符串长度 (不包括’\0’,sizeof包括)’\0’】 |
见左 |
||
小写字符串 |
strlwr |
char* |
char* |
将字母全小写 |
修改后的形参 |
||
大写字符串 |
strupr |
char* |
char* |
将字母全大写 |
修改后的形参 |
||
stdlib .h |
随机数函数 |
rand |
\ |
int |
随机生成0到的整数 |
见左 |
|
1、 格式字符(%)
2、 修饰符
(先取小数,四舍五入;再看整数,如果整数位数+小数点(也算一位)+小数位数小于总位数,则补空格,若此时加上整数位数超了,则以实际位数为准)
(若n=0,则表示不要小数部分)
3、 格式化输入输出
注:scanf()不能指定浮点数的精度,如 %5.2f错误。
n 对scanf() 函数输入时要看前面占位符之间有无逗号,有则输入时也要加,无则别加否则结果错误。
n scanf()是以删除的方式从缓冲区读取字符(根据字符宽度),遇到非目标类型字符则跳转至下一占位符,读取后根据数据字节舍弃字符。
ü 如scanf_s(“%1c%2c%3c”,&m,&n,&p) 输入1_22_333,则会依次读取1、_ 2、2_3,然后受限于字符字节,m、n、p分别为第一位1、_、2
ü 又如scanf_s(“%2d”,&a);输入字符2a3,只读取到2就停止, 然后由于字符宽度,最终输出_2。
ü 总结:根据输入数据类型要求(优先考虑)和字符宽度(数据类型相同时考虑)要求读取,根据字节长度舍弃,再根据输出字符宽度要求补全。
n 数据分隔符:空格、Enter、Tab
n 对于高版本的VS,使用scanf_s读入%c或%s的时候必须多传入一个参数用来指定读取的长度,否则会出错
(scanf不会读取空格、Tab、回车)
l (字符串输入的时候,有首地址就够了)
l printf占位符赋值是从右到左执行,输出是从左到右
l Printf返回的是输出字符的个数
%d, float/ (long) double: 0
%d, char: ASCII码值
%c, int: 该数对256取余后对应的字符
%c, float/ (long) double:空字符
%f, char/ int: 0.000000
4、 表中math.h下的函数double型均可替换为float或long double型,且保持一致
五、 选择结构
1、 特点/功能:根据不同情况做出不同选择
2、 表达式的真值:返回值不为0即为真,反之为假
3、 条件运算符(?:):基本形式x=(exp1)? (exp2):(exp3);exp1为真则x=exp2,反之x=exp3
4、 if语句:基本形式:if(exp) sentence; exp为真时执行sentence反之不执行
5、 else语句:基本形式:if(exp) sts1; else sts2; exp为真时执行sts1,反之执行sts2
6、 if语句的嵌套结构
7、 else if语句
8、 switch语句
(无视后面遇到的case值,直至遇到break停止)
(default在结尾则可以不加break,在中间要加)
9、 break语句:用于跳出switch语句或循环结构,详情见后
六、 循环结构
1、 特点/功能:重复相似语句,提高程序效率
2、 while循环:基本形式:while(exp) sts; exp为真时执行sts并返回while语句继续判断
3、 do-while循环:基本形式:do{body;} while(exp);先执行一次然后同上
While循环后的while()后没有分号,do-while循环后的while后一定有个分号。
4、 for循环:基本形式:for(exp1;exp2;exp3){body;}从exp1进入;然后紧接着就判断exp2,若为真执行body,反之离开循环;执行完body后再经过exp3重新判断exp2,循环
5、 continue语句:用于循环结构中跳过本次循环回到判断语句
6、 break语句:离开循环体结构,若存在嵌套结构,则仅跳出当前所在循环体
易错:break语句不能用于循环语句和switch语句外的任何其它语句(√)
7、 goto语句:在存在标签(形式为name:)的情况下,使用goto name可以直接移动到标签所在位置并顺序执行语句
七、 数组与字符串
数组:一系列相互关联的变量之间的有序集合与统一定义
·下标(方括号[]):在定义的时候规定数列长度,在调用的时候表明序数
·调用时下标内可以是常量或变量表达式(方便了与循环的结合)
·(大部分知识点见上文 数据类型)
字符串:字符形式的数列,其赋初值方式可以是”xxx”或{‘x’, ’x’, ’x’, 0},二者等效
·字符串必须以终止符(\0)结尾,否则不能成为完整结构的字符串
·字符串从第一个字符读到终止符结束,和数组长度有异(定义长度时应长一点)
·单字符输入和格式化输入都不会带上终止符,而gets会自动添加
·终止符:’\0’或’\000’,即ASCII为0的字符(NULL)
·终止符的输出结果类似空格,但不是空格(space,32)
八、 自定义函数
1、 函数:函数是程序的组成单位,执行某一功能的模块。main函数是程序的主函数
2、 函数分类:
3、 自定义函数
基本格式:类型名 函数名(形参列表){body;}
4、 实参与形参
(可以是赋值了的变量,也可以是常量,还可以是有返回值的函数调用表达式,但不能是语句(语句带了;没有返回值))
5、 return语句
6、 主调函数与被调函数的关联
7、 函数的递归调用:在函数中调用自身,从而实现迭代等功能,是一种高级的循环
·分类:直接递归调用就是在函数a(或过程)中直接引用(调用)函数a本身
间接递归调用就是在函数a(或过程)中调用另外一个函数b,而该函数 b又引用(调用)了函数
8、 内部函数与外部函数:根据函数能否被其他源文件调用,将函数区分为内部函数和外部函数。
内部函数 static int fun(int a,int b)
外部函数(extern) int fun (int a, int b)
一般默认为外部函数
在需要调用此函数的文件中,用extern声明所用的函数是外部函数。
九、 指针
1、 指针变量是一类储存地址而非值的变量,以间接访问的方式读取值
2、 指针变量的定义:类型名 *变量名(对于char *a, b; 只有a是指针变量)
3、 只有指针变量能储存地址,而指针变量也只能储存地址
4、 指针变量的值变为0(NULL)时表示不指向任何变量
5、 对指针变量的赋值可以使用取地址符&,或是直接使用数组名或字符串名(本质是地址)
6、 对于int i=3, *p=&i; *p等价于i而不是3,故后置语句*p=4不会报错,而会将4赋值给普通整型变量i;
7、 要先对指针变量进行初始化才能解引用(*)
8、 对指针类型变量p,p+n的意义为p后的第n个有效地址,而不是简单加上n,至于相邻地址的间隔,与变量的类型等有关;
9、 数组a[2][2]地址顺序为&a[0][0],&a[0][1],&a[1][0],&a[1][1];
10、 注意:使用指针的时候应时刻注意指针指向对象
11、 特殊指针类型:
u 指针数组:char *arr[4]; arr先跟[]结合成为一个数组,再跟*结合成指针,即为指针数组。
u 数组指针:char (*pa)[4];
拓:既然pa是一个指针,存放一个数组的地址,那么在我们定义一个数组时,数组名称就是这个数组的首地址,那么这二者有什么区别和联系呢?
char a[4];,
a是一个长度为4的字符数组,a是这个数组的首元素首地址。既然a是地址,pa是指向数组的指针,那么能将a赋值给pa吗?答案是不行的!因为a是数组首元素首地址,pa存放的却是数组首地址,a是char 类型,a+1,a的值会实实在在的加1,而pa是char[4]类型的,pa+1,pa则会加4,虽然数组的首地址和首元素首地址的值相同,但是两者操作不同,所以类型不匹配不能直接赋值,但是可以这样:pa = &a,pa相当与二维数组的行指针,现在它指向a[4]的地址。
二维数组的指针:行指针常用数组指针表示,如char x[3][4];char(*p)[4]=x;(表示指向它行首元素,p+1则移动到下一行,*(p+1)表示整个第二行的元素,但放到表达式中自动转化为第二行首个元素的地址,如*(p+1)+1表示第二行第二个元素的地址,*(*(p+1)+1)表示第二行第二个元素的值,**p表示数组首行首元素的值)
l 函数的指针:如int max(int a, int b);
l 对应的函数指针为 int (*pmax)(int, int) = max;
l //也可以写作int (*pmax)(int a, int b);(=max是对其进行初始化)
12、 指针相减
指针相减=(地址1-地址2)/sizeof(类型) ——定律 ,记牢。
指针相减得出的结果就是两个元素相差的单元,地址1和地址2以%d求出结果,不要用十六进制,要用十进制。在同一个数组中,相邻元素相差1个单元,这一个单元不一定是一个字节,具体多少字节,看你当初是怎么分配的。
十、 字符串
1、 赋值:1)逐字符赋值
char c[20]={'c', ' ', 'p', 'r', 'o', 'g', 'r', 'a','m'}; // 给部分数组元素赋值//剩下的自动初始化为’\0’
char d[]={'c', ' ', 'p', 'r', 'o', 'g', 'r', 'a', 'm' }; //对全体元素赋值时可以省去长度//存储的时候没有’\0’
char str[4]; str[0] = 'a'; str[1] = 'b'; str[2] = 'c';str[3]=’\0’;//逐元素赋值要手动添加’\0’
2)字符串直接赋值(’\0’也被存入数组中)
char str[30] = {"c.biancheng.net"};
char str[30] = "c.biancheng.net";
char str[] = {"c.biancheng.net"};
char str[] = "c.biancheng.net";
注意:字符数组只有在定义时才能将整个字符串一次性地赋值给它,一旦定义完了,就只能一个字符一个字符地赋值了。如char str[7]; str = "abc123"; //错误
str[3] = '1'; str[4] = '2'; str[5] = '3'; //正确
2、 输入
3、 输出
易错总结: