一、C语言的关键字
C语言的关键字是一些编译器预先定义的具有一定具体含义的字符串。关键字共有32个,分为五大类:
1. 基本数据类型——(9个)
关键字 | 含义 |
---|---|
char | 软件操作的最小数据单元 8bit |
int | 系统单周期最大数据处理单元 32bit/64bit |
short | 特殊长度的限制符(不能大于int) 通常16bit |
long | 特殊长度的限制符(不能小于int) 通常32bit |
float | 浮点型数据,带小数点 通常32bit |
double | 浮点型数据,带小数点 通常64bit |
void | 空类型 |
signed | 带符号类型,用作数值 |
unsigned | 不带符号,用作内存 |
原码/补码/反码
机器数
一个数在计算机中的二进制表示形式带符号,正数为0, 负数为1,叫做这个数的机器数
例:十进制中的数 +3 ,机器数是00000011。-3 ,机器数是 10000011
真值
带符号位的机器数对应的真正数值称为机器数的真值。
例:0000 0001的真值 = +000 0001 = +1,1000 0001的真值 = –000 0001 = –1
原码
原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值。
反码
正数的反码是其本身,负数的反码是在其原码的基础上, 符号位不变,其余各个位取反。
补码
正数的补码就是其本身,负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)
为什么会有原码反码补码?
计算机无法判断符号(硬件难于实现),因此使用符号位参与运算。
- 首先来看原码:
计算十进制的表达式:1-1=0
1 - 1 = 1 + (-1) = [00000001]原 + [10000001]原 = [10000010]原 = -2
如果用原码表示, 让符号位也参与计算, 显然对于减法来说, 结果是不正确的。 - 为了解决原码做减法的问题, 出现了反码:
计算十进制的表达式:1-1=0
1 - 1 = 1 + (-1)
= [0000 0001]原 + [1000 0001]原
= [0000 0001]反 + [1111 1110]反
= [1111 1111]反 = [1000 0000]原
= -0
会有[0000 0000]原和[1000 0000]原两个编码表示0. - 于是补码的出现, 解决了0的符号以及两个编码的问题:
1-1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原
= [0000 0001]补 + [1111 1111]补
= [0000 0000]补=[0000 0000]原
这样0用[0000 0000]表示, 而以前出现问题的-0则不存在了.而且可以用[1000 0000]表示-128。
ASCII码表
Bin | Dec | Hex | 缩写/字符 | 解释 |
---|---|---|---|---|
0000 0000 | 0 | 00 | NUL(null) | 空字符 |
0000 1000 | 8 | 08 | BS (backspace) | 退格 |
0000 1001 | 9 | 09 | HT (horizontal tab) | 水平制表符 |
0000 1010 | 10 | 0A | LF (NL line feed, new line) | 换行键 |
0000 1101 | 13 | 0D | CR (carriage return) | 回车键 |
0010 0000 | 32 | 20 | (space) 空格 | |
00110000 | 48-57 | 30-39 | 0-9 数字 | |
01000001 | 65-90 | 41-5A | A-Z 大写字母 同字母大小写相差32 | |
01100001 | 97-122 | 61-7A | a-z 小写字母 | |
01111111 | 127 | 7F | DEL (delete) | 删除 |
2.自定义数据类型——(4个)
自定义数据类型相当于基本数据类型的集合。
关键字 | 含义 | 注意事项 |
---|---|---|
struct | 结构体 | 内存占用2字节或4字节对齐 |
union | 共用体(联合体) | 以最大的元素占用内存 |
enum | 枚举常量 | 枚举值是常量,不是变量。不能在程序中用赋值语句再对它赋值。只能把枚举值赋予枚举变量,不能把元素的数值直接赋予枚举变量。枚举元素不是字符常量也不是字符串常量,使用时不要加单、双引号 |
typedef | 数据类型别名 |
3.逻辑结构——(11个)
C语言的逻辑结构有三种:顺序,分支,循环
关键字 | 含义 |
---|---|
if、else | 分支结构 |
switch、case、default | 分支结构 switch条件只能是整形数字 |
do、while | 循环结构 先后顺序 条件循环 |
for | 循环结构 次数循环 |
continue | 跳转 跳出本次循环继续进行下次循环 |
break | 跳转 跳出当前循环进入下个语句 |
goto | 不建议使用 |
4.类型修饰符——(6个)
类型修饰符是对资源存放位置的限定
关键字 | 含义 |
---|---|
auto | 默认情况 局部变量存放于栈空间 |
register | 限制变量定义在寄存器上的修饰符 存放在寄存器,无法用&取地址 |
static | 静态 |
const | 定义为常量,防止被修改 |
extern | 外部引用 外部文件 |
volatile | 编译优化选项 |
static详解
- 修饰全局变量:定义全局变量为静态全局变量
存放在.data(初始化)和.bss(未初始化)
外部文件无法引用 - 修饰局部变量:定义为静态局部变量
存放区域为.data
生命周期为整个程序的生命周期,但依旧只有定义他的函数能够使用
值,初始化为0,每次调用会读取上次的值。 - 修饰函数:定义为静态函数
只能在本文件调用
const详解
- 修饰变量
定义变量为不可改变的。 - 修饰指针
const char *p 修饰的是*p,p指向的内容不能被更改
char * const p 修饰的是p,指针不能被更改
const char * const p 指针和内容都不能被更改 - 修饰函数
□ 修饰输入参数
值传递 无需const保护
指针传递 防止更改原有指针指向的内容,对参数内容只读不写
5.其它
关键字 | 含义 |
---|---|
return | 返回。 |
sizeof | 查看内存容量 |
二、运算符
1. 运算符的分类
类别 | 符号 |
---|---|
算术运算符 | 加 + 减 - 乘 * 除 / 取余 % |
逻辑运算符 | 与 && 或 || 非 ! |
问号运算 | ? : |
关系运算 | 小于 < 小于等于 <= 大于 > 大于等于 >= 等于 == 不等于 != |
位运算 | 左移 << 右移>> 按位与 & 按位或 | 按位异或 ^ |
赋值运算 | 等于 = 加等于 += 剪等于 -= 等等 |
三目运算 | 表达式A? 表达式B: 表达式C 如果表达式A为真,那么表达式B为整个表达式的值;为假 , 那么表达式C为整个表达式的值。 |
逗号运算 | 从左到右依次计算,最后表达式的值,作为整个表达式的值。 |
2. 运算优先级
优先级 | 运算符 | 结合方向 |
---|---|---|
1成员包含 | []数组下标 ()圆括号 .成员选择(对象) ->成员选择(指针) | 左到右 |
2单目运算 | -负号运算符 (类型)强制类型转换 ++自增运算符 –自减运算符 | 右到左 |
*取值运算符 &取地址运算符 !逻辑非运算符 ~按位取反运算符 sizeof长度运算符 | ||
3算术运算 | 加减乘除取余 | 左到右 |
4位移 | << 左移 >> 右移 | 左到右 |
5比较 | > 大于>=大于等于 < 小于 <=小于等于 | 左到右 |
==等于 !=不等于 | ||
6位比较 | &按位与 ^按位异或 按位或 | 左到右 |
7逻辑运算 | &&逻辑与 | |
8条件运算 | ?:条件运算符 | 右到左 |
9赋值运算 | =赋值运算符 /=除后赋值 *=乘后赋值 %=取模后赋值 | 右到左 |
10逗号 | ,逗号运算符 | 左到右 |
3. 神奇的运算
取余运算:
取一个范围的数(m% 100)+1 ===> res;得到M进制的一个个位数;循环数据结构的下标
逻辑运算:
返回值0与1 !与~不同
位运算:
<< 左移相当于乘以2 >> 右移相当于除以2
& 与0屏蔽用于清零 与1用于取出 | 或0保留用于取出 或1用于设置
三、C语言的内存使用
1. 指针
指针:内存类型资源地址
指针变量 : 存放指针这个概念的盒子。所有的指针在32位系统中都是4字节。
指针的类型:去掉变量后的内容
指针所指向的类型:去掉*后的内容
指针的值/叫指针所指向的内存区:指向内容的首地址
指针本身所占据的内存区:在32位系统中都是4字节
指针的加减N:将现有指针指向的内存区加减 指针指向类型的大小 * N
常见的指针类型:
表达式 | 含义 |
---|---|
int p; | 这是一个普通的整型变量 |
int *p; | 首先从 P 处开始,先与*结合,所以说明 P 是一个指针,然后再与 int 结合,说明指针所指向的内容的类型为 int 型.所以 P 是一个返回整型数据的指针 |
int p[3]; | 首先从 P 处开始,先与[]结合,说明 P 是一个数组,然后与 int 结合,说明数组里的元素是整型的,所以 P 是一个由整型数据组成的数组 |
int *p[3]; | 首先从 P 处开始,先与[]结合,因为其优先级比*高,所以 P 是一个数组,然后再与*结合,说明数组里的元素是指针类型,然后再与 int 结合,说明指针所指向的内容的类型是整型的所以P 是一个由返回整型数据的指针所组成的数组 |
int (*p)[3]; | 首先从 P 处开始,先与*结合,说明 P 是一个指针然后再与[]结合,说明指针所指向的内容是一个数组,然后再与 int 结合,说明数组里的元素是整型的.所以 P 是一个指向由整型数据组成的数组的指针 |
int **p; | 首先从 P 开始,先与结合,说是 P 是一个指针,然后再与结合,说明指针所指向的元素是指针,然后再与 int 结合,说明该指针所指向的元素是整型数据. |
int p(int); | 从 P 处起,先与()结合,说明 P 是一个函数,然后进入//()里分析,说明该函数有一个整型变量的参数然后再与外面的 int 结合,说明函数的返回值是一个整型数据 |
Int (*p)(int); | 从 P 处开始,先与指针结合,说明 P 是一个指针,然后与()结合,说明指针指向的是一个函数,然后再与()里的int 结合,说明函数有一个 int 型的参数,再与最外层的int 结合,说明函数的返回类型是整型,所以 P 是一个指向有一个整型参数且返回类型为整型的函数的指针 |
int *(*p(int))[3]; | 从 P 开始,先与()结合,说明 P 是一个函数,然后进入()里面,与 int 结合,说明函数有一个整型变量参数,然后再与外面的*结合,说明函数返回的是一个指针,然后到最外面一层,先与[]结合,说明返回的指针指向的是一个数组,然后再与*结合,说明数组里的元素是指针,然后再与 int 结合,说明指针指向的内容是整型数据.所以 P 是一个参数为一个整数且返回一个指向由整型指针变量组成的数组的指针变量的函数. |
int *(*p[3])(void*); | 首先和[]结合,说明p是一个数组 |
然后和*结合,说明数组中的每个元素都是一个指针,
然后和()结合,说明指针指向的是一个函数,
最后,与外层相结合说明这个函数的输入参数为void*型,返回值为int * 型
所以p是一个含有三个元素的数组,每个数组元素都是一个参数为一个整数且返回一个指向整型指针的函数.
2. 数组
数组是具有一定顺序关系的若干个变量的集合,组成数组的各个变量称为数组的元素。
数组的元素地址空间是连续的。
<存储类型> <数据类型 > <数组名>[<表达式>]
数组是内存的一种分配方式,数组名是一个常量符号,一定不要放到=的左边。
数组的赋值
- 按照标签逐一处理
int a[10]; [ 0 - 9 ]
a[0] = xx
a[1] = yy;
- 空间定义时,就告知编译器的初始化情况,空间的第一次赋值,初始化操作
int a[10] = 空间;
- C语言本身,CPU内部本身一般不支持空间和空间的拷贝
int a[10] = {10,20,30}; ====> a[0] = 10; a[1] = 20; a[2] = 30; a[3]=0;
3. 内存分布
内存的属性: 1、大小 2、在哪里
运行时
名称 | 含义 | 访问权限 | 备注 |
---|---|---|---|
内核空间 | 应用程序不许访问(3G-4G) | ||
栈空间 | 局部变量 | RW | 向下增长 |
运行时的堆空间 | malloc | RW | 向上增长 |
全局的数据空间 (未初始化) 0 | static | RW | bss |
全局的数据空间(初始化的) | static | RW | data |
只读数据段 | “hello world” 字符串常量 | R | TEXT |
代码段 | code | R | TEXT |
存储时:
名称 | 标识 | 访问权限 | 备注 |
---|---|---|---|
数据区(未初始化) | bss | RW | |
数据区(初始化的) | data | RW | |
代码段 | code | R | TEXT |
栈空间:运行时,函数内部使用的变量,函数一旦返回,就释放,生存周期是函数内
堆空间:运行时,可以自由,自我管理的分配和释放的空间,生存周期是由程序员来决定
四、函数
1. 函数概述
一堆代码的集合,用一个标签去描述它,为了实现代码的复用化
标签 —– 函数名,函数具备3要素:
1、函数名 (地址)
2、输入参数
3、返回值
在定义函数时,必须将3要素告知编译器。
2. 输入参数
承上启下的功能
- 调用者:
函数名(要传递的数据) //实参 - 被调者:
函数的具体实现
函数的返回值 函数名(接收的数据) //形参
值传递
上层调用者 保护自己空间值不被修改的能力
地址传递
上层,调用者 让下层 子函数 修改自己空间值的方式
- 子函数看看空间里的情况 const *
- 子函数反向修改上层空间里的内容 char *
3. 返回值
提供启下功能的一种表现形式