嵌入式从入门到入土:C语言2
注意:不管是常量,还是变量其实都是存在内存之中,常量是存储在常量池的变量根据情况存储,基本类型是存放在栈内存的。
栈内存:栈是一种线性数据结构,其内存分配是静态的,由程序自动向操作系统申请分配以及回收,访问速度快,申请的内存单元的大小是固定值,使用方便,但程序员无法控制。如函数参数、局部变量、临时变量等等
堆内存:堆则是一种树形结构,其内存分配是动态的。堆内存的大小通常比栈大得多,由程序员自己申请、自己释放。否则发生内存泄露。典型为使用new申请的堆内容。
常量与变量
变量
概念:
在程序执行过程中其中的值可以被改变的量,称之为变量。
-
变量代表内存中具有特定属性的一个存储单元,它是用来存储数据的,也就是存放变量的值。
-
变量应该有一个名字,以便于通过名字访问变量。
格式
数据类型 变量名类型;
举例:
#include <stdio.h>
int main()
{
//①声明变量初始化
int age = 21; //注意:这里的 = 不是我们所认为的相等,在这里代表赋值操作,意思是将右边的值赋给左边的变量。
//②先声明,再赋值
int count;
count = 10;
//③初始化并修改变量的值
int number = 12;
printf("%d\n",number);//12,%d是十进制int的格式化符
number = 22;
printf("%d\n",number);//22,我们对同一个变量进行赋值的时候后面的值会覆盖掉前面赋的值
}
基本类型:我们创建变量的同时在内存上开辟对应的内存空间
命名规则:
- 变量名必须以字母
(a~z)
或者下划线(_)
开头,后面可以跟若干个**字母、数字或下划线;
** - 变量名不能与C语言中已经存在的标识符(如:int,float,void,if,break等)重名;
变量名、变量值、变量所占存储单元之间的关系:
标识符
-
标识符的定义:
用来表示对象的名字的有效字符。对象包括变量、常量(宏定义)、数组、函数、类型(结构体、共用体、枚举)等。也就是标识符就是对象的名字。
-
标识符的构成:
- C语言规定标识符只能由字母、数字和下划线3种字符构成,且第一个必须为字母或者下划线。举例:number,_int
- 编译系统对大小写敏感。==变量名和函数名一般用小写字母+下划线,常量名和枚举名一般用大写字母+下划线。==举例:变量
set_count
函数set_count()
常量SET_COUNT
-
C语言中有3类标识符
-
关键字:
有32个,系统有特定的含义和用途:如:float,int,if,else等,不能用作自定义表示符(变量和函数)
-
系统预定义的标识符:
如系统提供的库函数名sim,printf,main,scanf以及预处理命令define,include等。
-
用户标识符:
用户定义的标识符,用来给程序的变量、自定义函数、符号常量、数组、结构体、共用体、文件等命名。
-
注意:
在C语言中,要求对所用到的变量使用前必须先强制定义,即:先定义,后使用。
- C语言中有32个关键字,不允许用户用来定义标识符。
12个预处理命令:
说明:
一个类型说明语句可以同时定义多个类型的变量,各个变量之间使用逗号 ","
分隔,多个同类型的变量也可以用多个类型说明语句定义:
//一个类型说明语句可以同时定义多个类型的变量
int a,b,c,d;//同类型
int a1=3,b1=4,c1=5,d1 = 6;
//多个同类型的变量也可以用多个类型说明语句
int a;
int b;
int c;
int d;
int a1 = 3;
int b1 = 4;
int c1 = 5;
int d1 = 6;
-
用类型说明语句定义的变量只是说明了为这些变量分了存储空间。以便于存放与之相同类型的数据,在未对这些变量赋值前,这些变量中的值是随机的;
-
C语言允许在定义变量的同时为变量赋初始值;
-
在为长整型变量初始化初始化或者赋值时,如果被赋值的数据为基本整形常量,则C编译系统自动将被赋值数据转换成与相应变量类型一致。
long a = 12; //左边是long类型变量,右边是int常量,当完成赋值操作后,右边的12的类型转换为long
-
由于各种整形变量所占的字节数有限,因此,我们所能存放的整数有一定范围。
基本类型数据
基本类型数据都是运行在内存中,在内存中是以二进制补码的方式存储的。
整型数据
用来存放整型数据的变量
我们定义一个整型的变量,C编译系统实际是在内存中分配了能够存储一个整型数据的存储空间,并用变量名来标识这个空间,对该空间的使用也就可以通过变量名来访问。
若不知道你所用的C汇编系统对变量分配的存储空间的大小,可用sizeof运算符查询,如:
printf("%d,%d,%d\n"sizeof(int),sizeof(short),sizeof(long));// 4,2,8
案例
整型变量的定义和使用。
#include <stdio.h>
int main()
{
int a,b,c,d;// 定义有符号整型变量,可以存储负数,也可以存储正数。
unsigned int u;// 定义无符号整型变量,只能存储正数,正数的范围会变大。
a = 12;
b = -24;
u = 10;
c = a + u,d = b + u;
printf("a+u=%d,b+u=%d\n",c,d)
}
整型数据在内存中的存放形式
-
数据在内存中是以二进制的形式存放的
如果有以下语句:
int i; //定义i为存储整型的变量 i = 10; //给i赋整数为值
则十进制数10的二进制形式为1010,则内存中实际的存放形式为
-
实际上,数据在内存中是以**
补码
**形式表示的。- 符号位是左边第一个(1表示负数,0表示正数)。
- 正数的补码、反码和原码(该书的二进制形式)都相同。
- 负数原码的补码是将该数绝对值的二进制形式,按位取反再加1(反码加1 = 补码)
- 负数原码的反码除符号位之外都按位取反得到反码。
- 负数的反码加1得到负数的补码。
原码针对应用层,补码针对计算机
可见在存放整数的存储单元中,一般情况下,最左边的一位用来表示符号位,符号位为0表示正数,符号位为1表示负数。
浮点型数据
概念:
用来表达实数(小数)的数据类型。
浮点型(实型)变量的分类
-
单精度浮点型(float):在64为系统中典型尺寸是4字节,精确到小数点后6位,%f
-
双精度浮点型(double):在64位系统中典型尺寸是8字节,精确到小数点后15~16位,%lf
-
长双精度浮点型(long double):在64位系统中典型的尺寸是16字节
**注意:**占用内存越多,能表达的精度越高
float f1; // 单精度
double f2; // 双精度
long double f3; // 长双精度
浮点型数据在内存中的存放形式
浮点型数据在内存中按照指数形式存放。系统将一个浮点数分成 小数部分 和 指数部分,分别存放。
类别 | 符号位 | 指数位 | 小数部分 | 指数偏移量 |
---|---|---|---|---|
单精度浮点数 | 1位[31] | 8位[30~23] | 23位[22~00] | 127 |
双精度浮点数 | 1位[63] | 11位[62~52] | 52位[51~00] | 1023 |
案例
-
要求:写出27.5在内存中的存放形式。
-
解析:
- 27.5的二进制为11011.1
- 指数表示法: 1.10111 ∗ 2 4 1.10111*2^4 1.10111∗24
- 指数:4,加上127,就是131,二进制:1000 0011
- 尾数(小数点后的数):10111,补够23位:1011 1000 0000 0000 0000 000
- 用二进制表示就是(符号位1位)0(指数位8位)1000 0011(尾数位23位)1011 1000 0000 0000 0000 000
※ 科学计数法(指数法):
C语⾔中⼀般浮点数有两种表⽰形式:
-
⼗进制形式:指的是数字必须以整数形式+⼩数形式组成,⽐如 10.0 、3.14 …符合规则,以10为底 数,并且科学计数法要在范围值之内。
-
指数形式:⼀般数学上对于⼩数可以以10为底进⾏表⽰ ⽐如3.14 * 10²,但是在使⽤英⽂半⻆输⼊法的 时候没办法输⼊上底或者下底,所以C语⾔规定以字⺟e或者E来表⽰指数,并且要求字⺟e或者E的前⾯ 必须有数字,字⺟e或者E的后⾯必须为整数。 -3.14E-2 2E-3 0.3E4
printf("%e", 10000000.00);
-
所以:E3 错误 因为E的前⾯有数据 ⽐如说 3.14E3 3.1e5.6 错误 因为 E的后⾯必须是整数
3.1e-2 对的 相当于 3.1 ∗ 1 0 − 2 3.1 * 10^{-2} 3.1∗10−2
1.01e-5 等价于 1.01 ∗ 1 0 − 5 1.01*10^{-5} 1.01∗10−5
字符型数据
**概念:**字符型变量用来存放字符常量。
定义:
char 变量列表;
案例:
#include <stdio.h>
int main()
{
char c1,c2;
C1 ='A';
C2 = 'B’
printf("c1=%c\n",c1);// c1=A,输出的是字符本身
printf("c2=%c\n",c2);// c2=B,输出的是字符本身
printf("c1=%d\n",c1);// c1=65(ASCII码表的编号)
printf("c2=%d\n",c2);// c2=66(ASCII码表的编号)
}
说明:一个字符变量只能存放一个字符。C编译系统都规定以一个字节的存储空间来存放一个字符,因此,一个字符型变量在内存中的大小是1字节(占1个字节)
字符数据在内存中的存储形式
将一个字符常量存入一个字符变量,实际上并不是把该字符本身存入内存单元中,而是将该字符对应的ASCII码存入内存单元。
例如:
char c1 = 'a',c2 = 'b';
'a'
的ASCII码为97、'b'
的ASCII码为98、他们在内存中的存放形式以对应ASCII码编号的二进制存放:
实际上按照二进制存放,形式为:
由此可见,在内存中字符数据的存储形式与整型数据类似,这就使得字符型数据和整型数据之间可以通用。也就是1个字符数据既可以字符形式输出,也可以以整数形式输出。
- 以字符形式输出时,编译系统将内存单元中的ASCII码转换成相应的字符,然后输出。
- 以整数形式输出时,直接将ASCII码作为整数输出。
- 因此,可以对字符数据进行算术运算,这时相当于对其ASCII码进行算术运算。
案例
要求:给字符变量赋整数值
#include <stdio.h>
main() //此时默认返回值类型是int
{
char c1,c2;
c1 = 97;
c2 = 98;
printf("%c %c \n",c1,c2);// 以字符形式输出,a b
printf("%d %d \n",c1,c2);//以整数形式输出,97 98
}
c1在内存的存储形式以及不同形式的输出,如下图所示:
小贴士:
字符数据只占1个字节,只能存放0~255范围内的整数。
注意:C语言中char变量不能存放汉字。
案例
要求:大小写字母转换
#include <stdio.h>
int main()
{
char c1,c2;
c1 ='a';// 97
c2 ='b';// 98
// 转大写
c1 = c1 - 32;// 赋值运算,运算规则是,由右到左
C2 = c2 - 32;
printf("%c %c \n",c1,c2); //① A B ② 65 66 ③ 'A' 'B'//选 ①
}
注意:C语言允许字符数据与整数直接进行算术运算,可以相互赋值。
运算符
各类数值型数据间的混合运算
-
整型、实型、字符型数据间可以进行混合运算,如:
10 - 'a' * 1.5
运算时,参加运算的两个数据如果类型不同,则首先将其类型转换成一致
再运算,转换规则是:
将优先级低的类型转换到优先级高的类型,被称作自动类型转换。(小转大)
注意:
在混合运算过程中,系统所进行的类型转换并不改变原数据的类型,只是在运算过程中将其值变成同类型后在运算。
int a = 10; double c = a + 22.5;// a只是在运算过程中临时将其值变成double,但是a本身并没有改变类型。
-
C语言提供了==强制类型转换(大转小)==运算,可得到一个所需类型的数据,强制类型转换的形式为:
(类型名)(表达式) -------------------------------------- 小类型类型 变量名 = (大类型类型)大类型变量;
-
(double)a 将a的值转换成double类型
-
(int)(x+y) 将x+y的结果转换为int类型
-
(int)x+y 将x的值转换成int类型后与y进行相加
-
(float)(5%3) 将5%3的值转换成float类型
特别需要说明的是:在强制类型转换的过程中,并不改变原变量的类型,只是在运算过程中将其值转换类型后再运算。
-
案例
要求:强制类型转换
#include <stdio.h>
void main()
{
float x;
int i;
x = 3.6F;
i = (int)x;
printf("x=%f,i=%d\n",x,i);// x=3.6,i=3 实数转换整数,会丢失小数部分。
}
说明:x仍然为float类型,可见强制类型转换并不改变变量的类型。
C语言运算符和C算术表达式
C运算符
序号 | 名称 | 符号 | 序号 | 名称 | 符号 |
---|---|---|---|---|---|
1 | 算术运算符 | + - * / % ++ -- | 8 | 指针运算符 | * & |
2 | 关系运算符 | > < >= <= == != | 9 | 字节数运算符 | sizeof |
3 | 逻辑运算符 | ! && ` | ` | 10 | |
4 | 位运算符 | << >> ~(按位取反) ` | (按位或) ^(按位异或)` `&(按位与)` | 11 | 强制类型转换运算符 |
5 | 赋值运算符 | = += -= *= /= %= | 12 | 分量运算符 | . -> |
6 | 条件运算符 | ? : | 13 | 其他 | 函数调用运算符() |
7 | 逗号运算符 | , |
C表达式
所谓表达式就是将操作对象用运算符连接起来的符合C语法规则的式子。(运算数 + 运算符 = 表达式)
序号 | 名称 | 举例 | 说明 |
---|---|---|---|
1 | 算术表达式 | 2 + 6.7 * 3.5 + sin(0.5) | 计算结果是数值类型 |
2 | 关系表达式 | x > 0, y <= z + 6 | 计算结果是布尔类型,或0和非0 |
3 | 逻辑表达式 | x>0 && y>0 | 计算结果是布尔类型,或0和非0 |
4 | 赋值表达式 | a = 5.6,sum += i | 规则:从右往左 |
5 | 逗号表达式 | x = 3,y += 4,z -= 8 | 分隔,并列,结果是最后一个表达式的值 |
C语言规定了运算符的优先级和结合性。在表达式求值时,按运算符的优先级别的高低次序执行。如果运算对象两侧的运算符优先级别相同,如a+b+c,则按照规定的“结合方向”处理。