导图社区 第02课数据类型常量变量及运算符
auto说明的变量只能在某个程序范围内使用(局部变量),通常在函数体内或函数中的复合语句里。(默认是随机值)。
编辑于2022-04-02 16:19:38第02课 数据类型、常量、变量及运算符
课时一 数据类型
数据类型的分类
基本类型
整型
signed short/int/long/long long
unsigned short/int/long/long long
字符型 char
实型 float double
枚举型 enum
构造类型
数组
结构体 struct
共用体 union
指针类型
在C语言里地址叫指针 在C语言里数组本质上其实也是指针,即:*a等同于a[]
空类型
void
基本数据类型
bool类型
要想在程序中使用bool类型,有两种方式
引入头文件#include<stdbool.h>
在定义bool类型的变量时,使用“_Bool 变量名”的形式, 因为“_Bool”是一种基本数据类型
注:如果在程序中用到了true或者false,还是要引入头文件#include<stdbool.h>
char类型
char的正式名称其实叫pure char,C/C++标准规定char的类型是实现相关的,可以是signed char,也可以是unsigned char。
一般编译器默认为signed char
short类型
int类型
long类型
long long类型
通过头文件#include<limits.h>可以实现指令调用数据类型的值域
强制类型转换
强制数据类型的转换是指采用某种方式将某种数据类型强制转换成指定的数据类型。 包括显式的数据类型转换和隐式的数据类型转换
强制类型转换符后面的表达式如存在复杂运算,一定要用小括号括起来
强制类型转换是一种不安全的转换,一般都是将高级类型转换成低级类型,要丢失数据的精度
注:强制类型转换并不改变表达式中变量的数据类型和其值
课时二 常量
基本数据类型的常量
常量是指在程序运行期间其数值不发生变化的数据
整数常量
整数可以是十进制数、八进制数或十六进制数
如要将一个二进制数换算成八进制,只需将二进制串划分成每三个为一组(如果需要的话,在前面补零),然后将三位一组的位串替换为相应的八进制数字即可
如果需要将八进制数换算为十六进制,只需将八进制数换算为二进制,然后再换算为十六进制即可(十六进制是四个二进制数为一组)
浮点常量
浮点常量又称为实数,一般含有小数部分
在C语言中,实数只有十进制的实数,分为单精度和双精度
单精度float
单精度浮点数在机内占4个字节
单精度浮点数有效数字8位
双精度double
双精度浮点数在机内占8个字节
双精度浮点数有效数字16位
实数有两种表示方法,即一般形式和指数形式
指数常量
指数形式的实数一般是由尾数部分、字母e或E和指数部分组成
字符常量
字符常量是指一个单一字符,其表示形式是由两个单引号包括的一个字符
在C语言中,字符常量具有数值,其数值就是该字符的ASCII码值
可以把字符常量看做一个字节的正整数
A对应65,a对应97 字符0对应48
字节和字符的区别
字节(Byte)是计量单位,表示数据量多少,是计算机信息技术用于计量存储容量的一种计量单位,通常情况下1字节等于8bit
字符(character)计算机中使用的字母、数字、字和符号,比如‘A’'$'‘&’等
一般在英文状态下一个字母或字符占用一个字节,一个汉字占用两个字节
英文标点占一个字节,中文标点占两个字节
%c 输出一个单一的字符
字符串常量
字符串常量是指用双引号括起来的一串字符来表示的数据
'\0'是判定字符数组结束的标识,表示这串字符到结尾了,即 '\0'是字符串的结束符,任何字符串之后都会自动加上'\0'
注:在字符数组中'\0'是占一个位置的
%s 输出一个字符串
标识常量
所谓标识常量是指用标识符代替常量使用的一种常量, 其名称通常是一个标识符
标识常量也叫符号常量,一般用大写英文字母的标识符
使用标识常量之前必须预先定义,形式为: #define<标识常量名称或符号常量或宏名称><常量> 例如:#define PI 3.1415926
定义一个宏名字之后,可以在其他宏定义中使用, 例如:#define AREA 2*PI*3
注:宏定义的“原样展开”陷阱,对于计算表达式记得要加括号 例如: #define ONE 1 #define TWO (ONE+ONE)
课时三 变量
变量的基础
变量在程序中用变量名表示,变量名由用户根据其用途来命名
变量名由字母、数字、下划线组成,不能以数字开头,不能和C的关键字重名
在程序运行时,变量占据存储空间的大小由其数据类型决定
变量在内存空间中的首地址,称为变量的地址
变量的说明
变量在程序中使用时,必须预先说明它们的存储类型和数据类型
变量说明的一般形式是: <存储类型> <数据类型> <变量名>;
<存储类型>是关键词auto(默认的)、register、static和extern
<数据类型>可以是基本数据类型,也可以是自定义的数据类型
缺省——即系统默认状态,意思与“默认”相同
变量的<存储类型>
auto
auto说明的变量只能在某个程序范围内使用(局部变量),通常在函数体内或函数中的复合语句里。(默认是随机值)
在函数体的某程序段内说明auto存储类型的变量时可以省略关键字auto
register
register称为寄存器型,register变量是想将变量放入CPU的寄存器中,这样可以加快程序的运行速度
如果申请不到就使用一般内存,同auto
register变量必须是能被CPU所接受的类型,这通常意味着register变量必须是一个单个的值,并且长度应该小于或者等于整型的长度
注:无法用“&”来获取register变量的地址,因为“地址”这个概念是针对那些存储在内存中的变量而言的
由于寄存器的数量有限,真正起作用的register修饰符的数目和类型都依赖于运行程序的机器
在某些情况下,把变量保存在寄存器中反而会降低程序的运行速度。因为被占用的寄存器不能再用于其它目的;或者变量被使用的次数不够多,不足以装入和存储变量所带来的额外开销。
%p用于打印地址,&用于取地址 例如: int i = 1; printf("%p",&i); //printf("0x%x",&i);
static
static变量称为静态存储类型的变量,既可以在函数体内,也可在函数体外说明。(默认是0)即可以修饰局部变量,也可以修饰全局变量。
注:static修饰的全局变量,其它文件无法使用,即使加了extern进行声明也无法使用,使得这个变量只能在当前文件使用。
局部变量使用static修饰时
在内存中以固定地址存放的,而不是以堆栈方式存放
只要程序没结束,就不会随着说明它的程序段的结束而消失,它下次再调用该函数,该存储类型的变量不再重新说明,而且还保留上次调用存入的数值
extern
当变量在一个文件中的函数体外说明(例如main函数外,也就是说其是一个全局变量),所有其他文件中的函数或程序段都可引用这个变量
extern称为外部参照引用型,使用extern声明的变量是想引用在其它文件中函数体外部说明的变量(全局变量) 但是static修饰的全局变量即使加了extern也是无法使用的,因为它只能在它所在的文件里使用
如果文件1要用文件2中的全局变量
在文件1中的函数体外部先用extern对变量进行声明
在编译时需要将两个文件同时进行编译:gcc 文件1.c 文件2.c
课时四 运算符
算术运算符
C提供的算术运算符:+,-,*,/,%,++等 注意:float、double不能取余
关系运算符
>,>=,<,<=,==,!=
逻辑运算符
! 逻辑反 && 逻辑与 短路特性——逢0截止,逢0则后面的语句就不执行了 || 逻辑或 短路特性——逢1截止,逢1则后面的语句就不执行了
位运算符
~ 位逻辑反 & 位逻辑与 | 位逻辑或 ^ 位逻辑异或——两个值不相同,则异或结果为真;相同则异或结果为假。(不同为真,相同为假) >> 右移位 << 左移位
赋值运算符
赋值运算符为“=”,其运算的一般形式为: <左值表达式>=<右值表达式>
赋值复合运算符其运算的一般形式为: <变量><操作符>=<表达式>
+= 加法赋值复合运算符 a+=b 等价于 a=a+b -= 减法赋值复合运算符 a-=b 等价于 a=a-b *= 乘法赋值复合运算符 a*=b 等价于 a=a*b /= 除法赋值复合运算符 a/=b 等价于 a=a/b %= 求余赋值复合运算符 a%=b 等价于 a=a%b &= 位与赋值复合运算符 a&=b 等价于 a=a&b |= 位或赋值复合运算符 a|=b 等价于 a=a|b ^= 位异或赋值复合运算符 a^=b 等价于 a=a^b >>= 位右移赋值复合运算符 a>>=b 等价于 a=a>>b <<= 位左移赋值复合运算符 a<<=b 等价于 a=a<<b
特殊运算符
条件运算符
条件运算符“?:”是三目运算符,其运算的一般形式为: <表达式1> ? <表达式2> : <表达式3> 等同于: if (表达式1) { (表达式2); } else { (表达式3); }
例如: int x=82, y=101; x>=y?x+18:y-100; //运算结果为1 x<(y-11)?x-22:y-1; //运算结果为60
x++>70,是先取x的值判断x>70是否成立,然后再执行x=x+1(x自加)操作 ++x>70,是先执行x=x+1(x自加)操作,然后再取x的值判断x>70是否成立
逗号运算符
执行顺序:从左→右依次执行,运算结果由最后一个表达式决定
例如: float x=10.5, y=1.8, z=0; z=(x+=5, y = x+0.2); //运算结果为z=15.7 z=(x=y=5, x +=1) ; //运算结果为z=6
sizeof运算符
sizeof(<数据类型或变量名>):返回一个对象或者类型所占的内存字节数(即以字节为单位)
注:sizeof只针对数据类型,而不针对变量的具体值!
运算符的优先级
C语言中i++和++i的区别
i++和++i都是C语言里的自增,但是它们自增的顺序不同: i++ 是i参与运算后,i的值再自增1; ++i是i自增1后再参与其它运算
C语言中return语句
return语句用来结束循环,或返回一个函数的值
return 0,说明程序正常退出,返回到主程序继续往下执行
return1,说明程序异常退出,返回主调函数来处理,继续往下执行
return 0或return 1对程序执行的顺序其实并没有影响,只是大家习惯于使用return (0)退出子程序而已
在函数中,如果碰到return 语句,那么程序就会返回调用该函数的下一条语句执行,也就是说跳出函数的执行,回到原来的地方继续执行下去
如果是在main函数中碰到return语句,那么整个程序就会停止,退出程序的执行
C语言printf格式控制符
C语言中的*和&符号
实例: int a = 10; int *b = &a; printf(“%d\n”, a); printf(“%d\n”, &a); printf(“%d\n”, b); printf(“%d\n”, *b); 结果: 10 6487620 6487620 10 思考:为什么&a和*b的值不一样?
变量a本质上代表一个存储单元。CPU通过该存储单元的地址访问该存储单元中的数据。 所以a本质上代表两个值:存储单元的地址和存储单元中的数据。于是就有了二义性。 为了消除这种二义性,C语言中规定:a表示存储单元中的数据,&a表示存储单元的地址。
a存储单元中的数据可以是一个普通数值,也可以是另一个存储单元的地址,比如:a=&b。 a=&b就是将b存储单元的地址存入a存储单元中。 C语言中规定:*a表示a中存储的地址所对应的存储单元中的数据,也就是说访问*a就等于访问b,于是*a提供了通过a访问b中数据的手段
a表示a对应的存储单元中的数据 &a表示a对应的存储单元的地址 *a表示:首先,要求a对应的存储单元中的数据一定是另一个存储单元的地址;于是*a表示另一个存储单元中的数据
当a声明的类型是int时,a中存储的是一个整数数值,通过a可以访问(读取或修改)这个数值 当a声明的类型是int*时,a中存储的是一个存储单元的地址,而该地址所对应的存储单元中存储的数据是一个整数数值,通过*a可以访问(读取或修改)这个数值。a==&*a都是该存储单元的地址 当a声明的类型是int**时,a中存储的是一个存储单元的地址,而该地址所对应的存储单元中存储的数据是另一个存储单元的地址,另外这个存储单元中存储的是一个整数数值,通过**a可以访问(读取或修改)这个数值
在C语言里,地址叫指针 在C语言里,数组本质上其实也是指针,即:*a等同于a[]
Linux中的程序运行过程
gcc datatype.c -o datatype输出可执行文件datatype
预处理
gcc datatype.c -E -o datatype.i 表示让gcc只进行“预处理”就行了
所谓的“预处理”,就是把程序中的宏展开,把头文件的内容展开包含进来等等一些编译前的预处理操作,然后-o保存在datatype.i文件里
编译
表示让gcc只进行“预处理编译”就行了
汇编
表示让gcc只进行“预处理编译汇编”就行了
链接
表示让gcc只进行“预处理编译汇编链接”
运行
./datatype