1、C语言程序环境安装与设置
以下关于c语言学习均使用的是VS2022,它是一个集成开发环境(IDE):一般包括代码编辑器、编译器、调试器和图形用户界面等工具。它的优点是安装简单无需多余配置使用方便,它的缺点是安装包较大。关于环境的安装参考以下教程:https://www.bilibili.com/video/BV11R4y1s7jz/
2、C语言程序结构
它们的名称和具体作用如下:
3、C语言的基本语法
它们的名称和具体作用如下:
关键字 | 作用 |
auto | 声明自动变量 |
break | 跳出当前循环 |
case | 开关语句分支 |
char | 声明字符型变量或函数返回值类型 |
const | 定义常量,如果一个变量被 const 修饰,那么它的值就不能再被改变 |
continue | 结束当前循环,开始下一轮循环 |
default | 开关语句中的"其它"分支 |
do | 循环语句的循环体 |
double | 声明双精度浮点型变量或函数返回值类型 |
else | 条件语句否定分支(与 if 连用) |
enum | 声明枚举类型 |
extern | 声明变量或函数是在其它文件或本文件的其他位置定义 |
float | 声明浮点型变量或函数返回值类型 |
for | 一种循环语句 |
goto | 无条件跳转语句 |
if | 条件语句 |
int | 声明整型变量或函数 |
long | 声明长整型变量或函数返回值类型 |
register | 声明寄存器变量 |
return | 子程序返回语句(可以带参数,也可不带参数) |
short | 声明短整型变量或函数 |
signed | 声明有符号类型变量或函数 |
sizeof | 计算数据类型或变量长度(即所占字节数) |
static | 声明静态变量 |
struct | 声明结构体类型 |
switch | 用于开关语句 |
typedef | 用以给数据类型取别名 |
unsigned | 声明无符号类型变量或函数 |
union | 声明共用体类型 |
void | 声明函数无返回值或无参数,声明无类型指针 |
volatile | 说明变量在程序执行中可被隐含地改变 |
while | 循环语句的循环条件 |
注意事项:
1、注释分为单行注释 // 和多行注释 /*...*/
2、标识符由大小写字母或下划线为起始,后跟大小写字母、下划线0~9的数字, 标识符中的字母分大小写,数字不能作为开头:
以下是有效的标识符书写格式:
mohd zara abc move_name a_123
myname50 _temp Mohd a23b9 retVal
4、C语言数据类型
C语言内置数据类型
字符型
名称 | 书写格式 | 内存大小 | 取值范围 |
字符型 | char | 1字节 | -128到127或0到255 |
无符号字符型 | unsigned char | 1字节 | 0到255 |
整型
名称 | 书写格式 | 内存大小 | 取值范围 |
短整型 | short | 2字节 | -32,768到32,767 |
无符号短整型 | unsigned short | 2字节 | 0到65,535 |
整型 | int | 4字节 | -32,768 到 32,767 或 -2,147,483,648 到 2,147,483,647 |
无符号整型 | unsigned int | 4字节 | 0 到 65,535 或 0 到 4,294,967,295 |
长整型 | long | 4字节 | -2,147,483,648 到 2,147,483,647 |
无符号长整型 | unsigned long | 4字节 | 0 到 4,294,967,295 |
更长整型(C99引入) | long long | 8字节 | -9223372036854775808到9223372036854775807 |
无符号更长整型 | unsigned long long | 8字节 | 0到18446744073709551615 |
浮点型
名称 | 书写格式 | 内存大小 | 取值范围 | 精度 |
单精度浮点型 | float | 4字节 | 1.2E-38到3.4E+38 | 可以精确到小数点后六或七位 |
双精度浮点型 | double | 8字节 | 2.3E-308 到 1.7E+308 | 可以精确到小数点后十五或十六位 |
高精度浮点型 | long double | 8字节 | 3.4E-4932 到 1.1E+4932 | 可以精确到小数点后十九或二十位 |
布尔类型
名称 | 书写格式 | 内存大小 | 取值范围 |
布尔类型 | __bool | 4字节 | true和flase |
整型与浮点型之间的类型转换
整型转浮点数涉及浮点数在内存中的存储方式:
根据国际标准IEEE(电气和电子电工协会)754,任意一个二进制浮点数V可以表示成下面的形式:
V = (-1)^S * M * 2^E
- (-1)^S表示符号位,当S=0,V为正数;当S=1,V为负数
- M表示有效数字,M大于等于1小于2
- 2^E表示指数位
V = 5. 0 (十进制) V = 5.5 (十进制)
=101.0 (二进制) = 101.1 (二进制)①
=1.01 * 2^2 =1.011 * 2^2 //与十进制科学计数法类似,这里将10换为2
=(-1)^0 * 1.01*2^2 =(-1)^0 * 1.011 * 2^2
即S = 0;M = 1.01;E=2; 即S = 0;M = 1.011;E=2;
①:因为二进制的每一位都有权重,比如11111.11,小数点前面的1就是2^0、2^1、......、2^n
而小数点后面的1每一个代表的就是2^-1、2^-2......、2^-n而相对应的就是0.5、0.25......
IEEE 754规定:
对于32位的浮点数,最高位存储符号位S,接着八位存储指数E,剩下的23位存储有效数字M
对于64位的浮点数,最高位存储符号位S,接着十一位存储指数E,剩下的52位存储有效数字M
浮点数存的过程:
IEEE 754 对有效数字M和指数E,有一些特别规定:
对有效数字M:在计算机内部保存M时, 默认这个数的第⼀位总是1 ,因此可以被舍去,只保存后⾯的小数部分。⽐如保存1.01的时候,只保存01,等到读取的时候,再把第⼀位的1加上去。这样有利于节省1位有效数字。以32位浮点数为例,留给M只有23位,将第⼀位的1舍去以后,等于可以保存24位有效数字,结果会更精确。
对指数E:⾸先,E为⼀个⽆符号整数,这意味着,E为32位浮点数时的取值范围为0~255;E为4位浮点数时的取值范围为0~2047。(E分别占八个和十一个比特位)但是,科学计数法中的E是可以为负,所以IEEE 754规定,存⼊内存时E的真实值必须再加上⼀个 中间数 ,对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023。⽐如:2^10的E是10,所以保存成32位浮点数时,必须保存成10+127=137,即10001001。
我们来分析一段代码来加深理解:
int main() { float a = 5.5; return 0; }
解析:
通过上述的浮点数存的过程我们可以得到这样的解题思路:
float a = 5.5; //S E M //0 10000001 01100000000000000000000 //01000000101100000000000000000000 //0100 0000 1011 0000 00000000 00000000 // 4 0 b 0 00 00 //二进制转十六进制表示 //0x40b00000 //最终结果
查看内存窗口:
浮点数取的过程:
E不全为0或不全为1
E= 计算值 + 127 / 1023 、M取小数部分,后面不够的补零
E全为0
E=1-127(或者1-1023)M还原为0.xxxxxx的小数形式
E全为1
如果有效数字M全为0,表⽰±⽆穷⼤(正负取决于符号位s)
下面正式开始浮点数与整数之间的类型转换:
# include <stdio.h> int main () { int n = 9 ; float *pFloat = ( float *)&n; printf ( "n 的值为: %d\n" ,n); printf ( "*pFloat 的值为: %f\n" ,*pFloat); *pFloat = 9.0 ; printf ( "num 的值为: %d\n" ,n); printf ( "*pFloat 的值为: %f\n" ,*pFloat); return 0 ; }
分块分析:
//以整数形式存以整数形式取,存的是什么样子读取的就是什么样子 int n = 9; printf("n的值为:%d\n",n);//结果为9
//以整数形式存以浮点数形式取,直接将整数转换为补码形式对浮点数进行取操作 int n = 9; 0 00000000 000000000000000000001001 9的补码分解成用SME的形式 此时E全为0,则E=1-127,M还原为0.xxxxxx的小数部分 (-1)^0*0.00000000000000000001001 * 2^-126 1*(一个近似于0的数) 0.000000...... 打印结果 printf ( "*pFloat 的值为: %f\n" ,*pFloat); ———————————————— 版权声明:本文为CSDN博主「无聊看看天T^T」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/m0_73975164/article/details/133164556
//以浮点数形式存以整数形式取,先进性浮点数存操作将浮点数转换为补码的形式然后输出 *pFloat = 9.0; 1001.0 (-1)^0*1.001*2^3 S = 0;M=1.001;E = 3 0 1000001 000100000000000000000000 printf ( "num 的值为: %d\n" ,n); 结果为1091567616
//以浮点数的形式存以浮点数的形式取,存的是什么样子读取的就是什么样子 *pFloat = 9.0 ; printf ( "*pFloat 的值为: %f\n" ,*pFloat); //结果为9.000000
运行结果:
整型与字符型之间的类型转换
简易版:
整型和字符型之间的类型转换涉及ASCII码:
关于ASCII码的具体信息可以通过此链接找到:ASCII码一览表,ASCII码对照表 (biancheng.net)
在这里我们只需要知道ASCII码的以下内容:
一个整数加上字符'\0'就可以得到它对应的字符型
一个字符型减去0就可以得到它对应的整数值
//整型转为字符型 int main() { char a= 65 + '\0'; printf("a=%c\n", a); return 0; }
//字符型转为整型 int main() { int a = ‘A’ - 0; printf("a=%d\n", a); return 0; }
如果是字符串转整型,那么就可以利用atoi函数
进阶版:
看这样一段代码:
int main() { char a = 5; char b = 127; char c = a + b; printf("%d", c); return 0; }
结果为-124而非132 ,这是因为C语言整型算术运算总是至少以整数类型(int)来进行,表达式中的字符型(char)和短整型(shotr)会在使用时转换为普通整型int / unsigned int,这种转换称之为整型提升。
下面是进行整型提升时a和b被分配内存的前后变化:
整型提升的意义在于:可以有效避免因为超出内存分配给它的范围而导致结果被丢弃,同时也增加了结果的精确度。
在进行正式的整型提升之前我们首先得知道原码、反码和补码的概念:
什么是原码、反码和补码?
整数的三种二进制表示方法叫做原码、反码和补码(无符号数没有原反补的概念)
三种方法均有符号位和数值位两部分组成,符号位为0表示负整数,符号位为1表示正整数,其中,符号位为整数二进制表示中的最高位(左边第一个),其余的二进制位都为数值位。
正整数的原码、反码和补码均相同,且符号位固定为1
负整数的原码、反码和补码均不同,且符号位固定为0
对于整型来说数据存放在内存中起始是补码的原因是:使用补码,可以将符号位和数值域统一处理;同时,加法和剑法也可以统一处理(CPU只有加法器)此外,补码和原码相互转换,其运算过程是相同的,不需要额外的硬件电路
对于四种码的变换方法遵循下表:(多加了个移码)
原码 | 反码 | 补码 | 移码 | |
真值为正 | 符号位变为0,其余各位不变 | 同原码 | 同原码 | 符号位变为1,其余各位不变 |
真值为负 | 符号位变为1,其余各位不变 | 符号位变为1,其余各位取反 | 反码加一 | 符号位变为0,其余各位取反加一 |
真值就是5、8、-122这种整数,原码的操作对象就是这些真值的二进制表示。
举一个已知真值求原码的例子:
我们设定[x]原为机器数,x为真值(关于机器数和真值的概念来自计算机组成原理)
①x为+122时,x = + 1111010,[x]原 = 0 1111010
②x为-122时, x = - 1111010,[x]原 = 1 1111010
如何进行整型提升?
①有符号整数提升是按照变量的数据类型的符号位来提升的,补码符号位为0则整型提升时高位补零,补码符号位为1则整型提升时高位补1.
②⽆符号整数提升,⾼位补0
字符型转整型的整型提升
进行整型提升之前要知道的是,整数在内存中都是以补码的形式操作的
int main() { char a = 5; //00000000 00000000 00000000 00000101 --- 5的补码 //00000101 -5的补码被截断后的结果赋值给a char b = 127; //00000000 00000000 00000000 01111111 --- 127的补码 //01111111 - 127的补码被截断后赋值给b
截断:char的二进制中只有八个比特位,而5和127是整型二进制位中有三十二个比特位,想要将其存入a中只能截断前面多余的二进制位 ==》一米长的洞塞入四米长的棍子
char c = a + b; //00000000 00000000 00000000 00000101 ---- a整型提升后的补码 //00000000 00000000 00000000 01111111 ---- b整型提升后的补码 //00000000 00000000 00000000 10000100 ---- a + b 的补码 //10000100 - c (a+b的补码被截断后存储到c中) printf("%d\n",c); //打印c的时候还是要进行整型提升,因为%d是按照打印10进制的形式打印有符号的整数 //1111111 11111111 11111111 10000100 ---c整型提升后的结果(补码) //10000000 00000000 00000000 01111100 ---c的原码 //-124 -打印c的结果 return 0; }
字符型与浮点型之间的类型转换
无符号字符型转为整型
int main() { unsigned char a = -1; //10000000 00000000 00000000 00000001 原码 //11111111 11111111 11111111 11111110 反码 //11111111 11111111 11111111 11111111 补码 //11111111 a截断后 printf("a=%d\n", a); //00000000 00000000 00000000 11111111 a整型提升结果(补码) //00000000 00000000 00000000 11111111 a的原码 //255 打印a的结果 return 0; }
字符类型转无符号整型
int main() { char a = -1; //10000000 00000000 00000000 1000000 a的原码 //11111111 11111111 11111111 01111111 a的反码 //11111111 11111111 11111111 01111111 a的补码 //10000000 a截断后 prntf("%u\n",a); %u打印无符号整数,无符号整数也是整数而a是char a所以仍需要整型提升 //11111111 11111111 11111111 10000000 a整型提升结果(看似是补码但其实不是) //4294967168 打印a的结果(打印无符号位整数,不需要再求出原码反码直接进行计算将其转换为具体的数即可,这是因为无符号数没原码反码补码的概念) }