C语言学习Part01
C语言知识
基础知识
BCPL->NEW B->C->UNIX->MINIX->LINUX->GCC
在BCPL语言的基础上由UNIX之父(肯・汤普逊)开发出了UNIX操作系统
在B语言的基础上由C语言之父(丹尼斯・里奇)开发出了C语言
补充:C++之父 本贾尼・斯特劳斯特卢斯、Java之父詹姆斯・高斯林、Python之父吉多・范罗苏姆
编译器:gcc
C语言标准
ANSI C:美国国家标准学会以及 ISO:国际标准化组织 推出的C语言标准
GNU C:GNU计划由Richard Stallman 公开发起 ,其在编写Linux时制作了GNU C标准
C语言优势
运行稳定
嵌入式开发领域优势巨大
具备可移植性
执行效率高
简洁
应用广泛
基础地位牢固
C语言开发简略流程
首先,编写以.c为结尾的源代码文件,其次通过gcc编译器进行编译生成.out文件,最后执行程序
helloword程序分析
#include <stdio.h>
int main(){
printf("Hello world!\n");
return 0;
}
C语言中以#开头的指令称为预处理指令,预处理指令要在预处理阶段进行
预处理指令的功能包括查找需要的头文件并把头文件内容导入到当前文件中
常见的导入头文件方式有<stdio.h> “stdio.h”前者为系统默认路径 后者为当前路径下
printf:C语言自身没有输入输出功能 需要借用stido.h头文件中的函数
main: 一个C语言程序中只有一个main函数,且从main函数开始并从main函数结束
return:main函数的返回值会告知程序运行的情况 0为正常 其他值则为有问题存在
main函数中的参数列表是用于接收linx命令行的参数
int main(){
return 0;
}
int main(int argc,char *argv[]){
return 0;
}
数据类型
C语言数据类型
基础数据类型
类型 | 字节大小 | 取值范围 | 格式占位符 |
---|---|---|---|
char | 1 | -128,127 | %hhd |
unsigned char | 1 | 0,255 | %hhu |
short | 2 | -32768,32767 | %hd |
unsigned short | 2 | 0,65535 | %hu |
int | 4 | -231,(231)-1 | %d |
unsigned int | 4 | 0,(2^32)-1 | %u |
long | 4/8 | -263,(263)-1/同int | %ld |
unsigned long | 4/8 | 0,(2^64)-1/同int | %lu |
long long | 8 | -263,(263)-1 | %lld |
unsigned long long | 8 | 0,(2^64)-1 | %llu |
float | 4 | ±3.4*10^38 | %f %g %e/E |
double | 8 | ±1.79*10^308 | %lf %g %e/E |
long double | 12/16 | %Lf |
自定义数据类型
struct结构体
union联合共用体
enum枚举
类型转换
隐式类型转换和类型提升
char short类型在运算时自动转换为int类型
当运算时有多个类型数据,则自动取类型最大的类型取值范围
当无符号和有符号数进行运算,自动转化为无符号数 则结果恒大于0
类型提升时数据会扩充
当数据为有符号时 则高位全部填符号位
当数据为无符号时,则高位全部填0
当赋值时溢出,则会自动舍弃多出的高位部分,因此当double赋值给float时往往会出现精度缺失,而赋值给整数时 整数只会保留整数部分
强制类型转换
a=(强制转换类型)b
数据存储
C语言在计算机中的存储方式均为二进制补码
对于有符号的数据来说,正数符号位为0 负数符号位为1
对于无符号的数据来说,所有位均用来存储数据
进制
进制就是计数的方式
基数 R进制 基数为R
位权 1243.567 = 1x10^3 + 2x10^2 +4x10^1 + 3x10^0 + 5x10-1+6x10-2 + 7x10^-3
二进制
逢二进一 只能通过0和1来表示
天然的逻辑值
C语言程序中不能直接使用二进制的字面值(10111001)b
八进制
逢八进一
在C语言中可以直接使用八进制的字面值 ,表示方式为0746 0265 0364 亦为以0开头的字面值整数
格式占位符 :%O/o
十进制
逢十进一
在C语言中可以直接使用八进制的字面值 ,表示方式为149 8462 6455的字面值整数 可以存在±
默认情况下为int 可以在字面之后加上 l ul L等字符来标识类型
十六进制
在C语言程序中可以使用十六进制
前缀为 0x或者0X
数值位用 0-9 以及a-f /A-F 来表示 a表示10 b-11 c-12 d-13 e-14 f-15
在嵌入式开发中,经常使用十六进制
格式占位符是 %x %X %#x
R进制
进制之间可以进行转换
十进制 转 R进制
除R取余
二进制 转 十进制
位权表示方式进行累加
二进制 转 八进制
从右往左,三个二进制位为一个八进制位,左边不够补0
二进制 转 十六进制
从右往左,四个二进制位为一个十六进制位,左边不够补0
八进制 转 二进制
一个八进制位对应三个二进制位
十六进制 转 二进制
一个十六进制位对应四个二进制位
原码 反码 补码
计算机中存储数据都是补码形式
整数
有符号正数:原码 反码 补码 均为正数的二进制
负数:原码为其正数的二进制,但最高位为1,反码则是对原码除了符号位之外的位取反 ,补码则是在此基础上加1
移码:一般情况下 移码是用来快速比较两个两个值的大小
表示形式为:补码+固定值(127/1023)
浮点数
小数点位置不固定
任何浮点数都可以表示为1.************* x2^n
float 小数点后6/7位 32位 符号位 1位 指数位8位 尾数位23位
double 小数点后15/16位 64 位 符号位1位 指数位11位 尾数位 52
指数位的数据需要加上127表示为移码 以此可以方便比较出指数大小
123.3125 二进制
0111 1011.0101 ==> 1.11 10110101 x 2^6
符号 指数 尾数
0 6+127 11 10110101 ...
0 1000 0101 11 10110101
0100 0010 1111 0110 1010 ----
0x42f6a000
特殊的浮点数的值
指数位全为0,尾数位全为0,符号位为0/1,值为0/-0
指数位全为1,尾数为全为0,符号位为0/1,值为 正无穷/负无穷 inf
指数位全为1,尾数为不全为0,符号位0/1 值为无效值
浮点数的零值并不完全等于零,需要根据类型进行小数点后尾数的比较
float f;
if(f == 0.0){//错误的判断方式
}
if(f < 0.000001 && f>-0.000001){//在这个区间之内,都是为"零"
}
字面值
整数字面值
十进制字面值 1,-1,1024,9527 , 1L, 1UL, 1ULL,1LL u/l/ul/ll/ull
八进制字面值 0777 , 01 , 03
十六进制字面值 0xabc, 0x11, 0X1AF ,0X0AA
浮点数字面值
3.14 1.79 -3.14
.15 0.15 -.15
3.14e7 2.53e-3 E
e前面可整可小数,但不能不写
e后面为整数,但可正可负 ,但必需要写
字符
ANSI 设定时,字符1个字节,能够存储ANSI所有的字符
1字节取值范围[-128,127] [0,255] 总共256个数值
字符本质是整数,用整数来代表不同的字符,ASCII码
ASCII编码
[0-127]
‘\0’ – 0
‘0’ – 48
‘A’ – 65
‘a’ – 97
字符字面值
-
‘a’ ‘b’ ‘Z’ ‘X’ 单引号
-
转义字符
'\n' '\r' '\0' '\\' '\'
-
八进制
'\101' ==> 'A' '\141' ==> 'a'
-
十六进制
'\x41' ==> 'A' '\x61' ==> 'a'
变量
变量的定义和赋值
C语言程序中需要存储一个数据时,需要定义变量
int x=10;//类型名 变量名 值 定义一个变量并初始化
int x; //定义一个变量
定义变量会为其规定类型,分配固定的内存,决定存储域、作用域、生命周期
一个变量只能定义一次,但可以声明多次(extern)
定义变量时可以对其初始化,如果不初始化 变量的值是随机的,定义后则可以进行赋值
int x=10;
x=11;
变量的使用
1、变量可以进行赋值
2、变量可以进行打印
变量命名要求
变量名称为标识符,变量只能由数字,字母,下划线组成,·且不能与C语言的关键字相同
以下为建议要求
见名知义 char name;
见名知类型 int iAge;
命名规则
大驼峰 FrontHuman
小驼峰 frontHuman
下划线 front_human
运算符
算数运算符
+ 加法 -减法 * 乘法
int a=10; int a=10; int a=10;
int b=20 int b=20 int b=20;
int c=0; int c=0; int c=0;
c=a+b; c=a-b; c=a*b;
//c为30 c为-10 c为200
/除法 %求余
int a=10; int a=10;
int b=20 int b=20;
int c=0; int c=0;
c=a/b; c=a%b;
c为0 c为10
a++ ++a 自增
本质上都是变量+1 区别是a++是先运算在改变变量的值 ++a则是 先改变变量的值 再运算
a-- --a 自减
本质上都是变量-1 区别是a--是先运算在改变变量的值 --a则是 先改变变量的值 再运算
由于不同编译器的过程不同 尽量不要对同一个变量同时自增自减
关系运算符
> >= < <= == !=
关系运算符得出的是此次关系判断的真假
则在C语言中表示范围时,要分开表示,否则会出现恒为真和恒为假
if(a < b < 2){//恒为真
}
if(a < b < 0){//恒为假
}
逻辑运算符
C语言当中用1和0来表示逻辑真和逻辑假
&& 与 当&&两边有一边为假 结果则为假 只有当两边都为真则为真
|| 或 当||两边有一边为真 结果则为真 只有当两边都为假则为假
! 非 当!后面的逻辑值为假时 则输出逻辑真 反之则输出逻辑假
由此特性可以得出C语言中的短路特性:
当&&前为假时 不需要再判断&&后的逻辑真假
当||前为真时,不需要再判断||后的逻辑真假
也就是不需要在执行逻辑运算符后的指令
赋值运算符
= 赋值
可以将=右边的值赋给等号左边的变量
特例:当x=(a,b,c)这样的形式,先从左往右计算a b c的值 再将最右边的c赋值给X
赋值运算符可以和某些运算符结合
a = a R b
a R = b
+= -= /= *= %= <<= >>= &= |= ^= 先将等号右边的值计算完 再和等号左边的值进行计算并赋值给等号左边的变量
位运算符
& | 和&& ||的逻辑规则相同,但要用0和1表示 并且运算符的两边是整数的二进制(同一位)
^ 异或 左右相同则为0 左右不同则为1
~ 按位对二进制数取反 0->1 1->0
>> 将二进制整体向右移n位
<< 将二进制整体向左移n位
sizeof
特殊的运算符 可以计算变量的类型长度
三目运算符
A?B:C
当A的逻辑为真时 则执行B
当A的逻辑为假时 则执行C
逗号运算符
可以将多个表达式,值,语句隔开
其他运算符
()运算符 可以将括号内的内容强制优先结合
[]下标运算符
. 访问结构体成员的运算符
->结构体指针间接成员访问运算符
运算符的优先级大致为:算术运算符 > 关系运算符 > 逻辑运算符 > 赋值运算符
具体的等级划分则为14个等级
语句
分支选择语句
if(条件){
执行内容
}
if(条件){
执行内容
}else{
执行内容
}
if(条件1){
执行内容
}else if(条件2){
执行内容
}else if(条件3){
执行内容
}
if(条件1){
执行内容
}else if(条件2){
执行内容
}else if(条件3){
执行内容
}else{
执行内容
}
switch(整形表达式){
case 1(结果之一的数字):
break;
case 2(结果之一的数字):
break;
case 3(结果之一的数字):
...
default:
break;
}
条件循环语句
for(init;condition;change){
forbody
}
init 为初始化
condition为执行条件
change为执行后改变
forbody为执行内容
while(条件){
循环体
}
do{
循环体
}while();
do while 和 while区别是 前者会先执行一次循环再进行判断 后者则是第一次执行循环就需要判断
跳转语句
goto
标签:
代码段
goto 标签;
可以通过goto直接访问到lable所在的位置继续执行代码
由于gotod的跳转有诸多限制和Bug所以不建议使用
break
1、在switch中可以使用break来跳出switch
2、在循环体中使用break可以直接跳出循环
continue
只能在循环体中使用,且只会跳出当次循环
函数
函数是构成C语言程序的基本单位,其目的是为了实现某个特定功能
函数的获取存在以下三种途径
1、标准库函数:在C语言中使用一些基础函数时,可以通过调用头文件来使用标准库函数
2、第三方库函数:其一可以通过下载别人的源代码,其二可以通过下载他人提供的静态库或共享库,使用时导入头文件,编译时连接库文件
3、自定义库函数:自己想要实现某项功能可以自己定义自己的函数
函数返回值类型 函数名(形参1,形参2...){
函数体;
return;
}
函数返回值类型
函数结束后,需要一个范围结果,可以根据需要进行自定义返回值类型
void 函数不需要返回值 int 返回值为整数 等等
即 return 返回值/不需要return
并且函数返回值的结果可以直接被调用
函数名
函数名也就是标识符,可以被多次声明,但只能被定义一次。函数名本质上是一个指针,对函数名取地址得到的就是函数名。
形参列表
和定义的变量不同,形参列表定义是,必须逐个定义。通过对函数传递形参,可以在不改变函数主体的情况下实现对不同数据的同一种功能的实现
函数体
函数功能的具体实现
函数的声明、定义和调用
函数的声明可以有多次,其仅仅是对函数的声明,不会定义函数
返回值类型 函数名(形参列表);
extern 返回值类型 函数名(形参列表);
函数的定义只能有一次
函数返回值类型 函数名(形参1,形参2...){
函数体;
}
对一个函数调用时 直接使用即可
函数名(实参);
在调用函数前只需要对其定义即可,声明与否不重要,但当在使用函数前为进行声明或定义,则会产生隐式声明,默认函数返回值为int ,如果在后续代码中有了函数的定义,则只会在返回值类型不同时警告或报错,如果没有,则会直接报错。