c语言
数据类型和基础
输出格式
- %5d :五个终端位宽,右对齐
- %-5d :5个终端位宽,左对齐
- %05d :5个终端位宽,右对齐不足补零
进制之间
-
八进制 编写时前面加0: 010==0
-
十六进制 ox: 0x12 == 18
-
二进制 01
-
十进制
-
不同数据的计算机存储和读取
-
存储
- 负数:补码
- 其他:原码
-
读取
-
有符号取:%d.%hd.%ld
- 最高位为0:原样输出
- 最高位为1:符号位不变取反+1
-
无符号取:%u,%x,%o,%lu
-
-
register
- 定义寄存器变量
volatile
- 作用:防止编译器优化,强制访问内存操作
typedef 给已有的类型取个别名
数据类型
-
基本数据类型
- char 1B
- short 2B
- int 4B
- long 4B(32位系统)
- double 8B
- float 4B
-
无符号和有符号
-
unsigned
- 特点:没有符号位
-
signed
-
特点:有符号位,1为负,0为正
-
-
-
测量类型长度
- sizeof()
-
数据类型的转换
-
自动类型转换
- signed int >> unsigned int >> long >>double
- char,short参加运算就用int型
-
强制类型转换
- 当前有效,后面不会更改
-
运算符
优先级
算术运算符
-
/
- 整数相除,结果取整
- 只要有一个浮点数,除法运算
-
%
-
取余
- 必须为整数
-
逻辑运算符
-
!逻辑非
- !0==真
- !真==0
-
&&逻辑与
- 同真则真
- 短路特性:前假不管后
-
|| 逻辑或
- 同假则假
- 短路特性:前真不看后
二进制运算符
-
& 按位与
- 全1为1,其他为0
- 特点:和1相与,保持不变,和0相与,清零
- 将固定位清零
-
| 按位或
- 全0为0,其他为1
- 特点:和0相或,保持不变,和1相或,置1
- 将固定位置1
-
~ 按位取反
- 0变1,1变0
-
^ 按位异或
- 相同为0,不同为1
- 特点:和0异或,不变;和1异或,取反
- 将固定位发生高低电频的翻转
-
<< 左移运算符
- 左边丢弃,右边补零
-
右移运算符
-
逻辑右移
- 右边丢弃,左边补零
-
算数右移
-
有符号数
- 正数
- 负数:左边补1
-
无符号数
-
-
其他运算符
-
? : 表达式?值1:值2
-
逗号运算符
- 表达式的值为最后一个表达式的值
-
符合运算符
- +=,-=,*=,%=
-
++ ,–运算符
判断语句
if
- if ()……
- if() …… else
- if() ……else if()……else if()……
switch
- break
循环语句
for(初始语句;循环条件;步进条件)
- break:跳出最近的一个循环
- continue:跳出本次循环
while(循环条件)
- 没有初始语句,没有步进语句
do……while(循环条件)
- 先执行后判断
goto
- 跳转到goto指向的地方
数组
概述:具有相同类型的变量,用连续的空间存储起来,这样的数据结构就是数组
数值数组
-
一维数值数组
-
定义时候[]里的值不能是变量
-
初始化:
-
全部初始化
- int arr[3]={1,2,3};
-
部分初始化
- int arr[3]={0};
-
-
输入和输出需要循环 arr[i]
-
-
二维数值数组
-
初始化
- 分段初始化:{}里的{}明确每一行
- 连续初始化:放满一行才能放下一行
-
字符数组
-
一维字符数组
-
初始化
- 逐个字符
- 字符串形式
-
遍历
- 循环逐个遍历
- 整体遍历%s
-
获取键盘字符串
-
scanf:遇到空格结束输入
-
gets:容易造成内存污染
-
fgets:解决两者问题,但是会有\n输入
- strtok
- strlen-1
-
-
-
二维字符数组
-
存放多个字符串,每个字符串占一行
-
输出
- 输出一个字符串,仅仅只需要用行标即可
- 输出某个字符时,用到行标和列标
-
键盘获取输入
- 字符串个数决定行数
- 字符串中最大长度决定列数
-
地址
- 二维数组名代表的是首行地址,+1跳过一行
- 对行地址取*,将变成当前行的第0列的列地址
-
函数
定义
- 返回值、函数名、形参、函数体
声明
- 返回值、函数名、形参
- 告诉编译器函数存在,请通过编译
调用
- 函数名+实参
函数参数
-
形参不写,实参可传,但得不到使用
-
实参
-
形参
- 本质:局部变量
- 函数定义时不会开辟空间,只有调用时才开辟空间
- 在函数结束的时候 才被释放
函数名
- 代表函数入口地址
返回值
- <=4B,存放寄存器
-
4B,存放栈区
全局函数和静态函数
-
全局函数
- 其他源文件可使用,需加extern
-
静态函数
-
static +函数
-
只能在当前源文件使用
-
可封装在全局函数里,被其他源文件使用
- 与全局函数位于同一个源文件
-
形参。返回值都存在栈区
变量
存放:
生命周期:
不初始化:
生效位置:
普通变量
-
普通局部变量
- 最近的{}生效
- 存放 栈区
- 生命周期:离开{}就回收
- 不初始化,内容不确定
- 同名就近原则
-
普通全局变量
- 定义在函数外边的变量,当前源文件都有效
- 存放 全局区
- extern:其他源文件也可使用
- 生命周期:进程结束释放
- 不初始化,内容为0
静态变量(static修饰)
-
静态局部变量
- {}生效
- 存放 全局区
- 生命周期:整个进程
- 不初始化,内容为0
- 只能被定义一次
-
静态全局变量
- 定义在函数外边,当前源文件生效
- 存放 全局区
- 生命周期:整个进程
- 不初始化,内容为0
宏(后面不加分号!!)
-
define
-
不带参数的宏:#define N 10
-
带参数的宏: #define N(a,b)a+b
-
做不到完整性
-
带参数的宏函数和普通函数的区别
宏函数:调用多少次,就展开多少次,执行代码的时候,没有函数调用的过程也不需要函数的出入栈,浪费了空间,节省了时间
普通函数:代码只有一份,存放在了代码段,调用时候出入栈,所以函数节省了空间,浪费了时间 -
子主题 3
-
-
-
undef
- 终止宏的作用
头文件包含
<> :从系统指定目录下寻找
“” : 从源文件所在目录下找,没找到就去系统指定目录下找
防止头文件重复包含
- 1、 #pragma once
- 2、 #infdef
#define
#endif
原码,反码,补码
只有负数在计算机中存储的是补码
补码的意义
- 1、将减法运算变加法运算
- 2、统一0的编码
指针
指针变量
-
本质是一个变量,存放内存的地址编号
-
32位平台,任何类型地址编号都是4字节
-
定义:*
- 前提:明确保存啥类型变量的地址
-
使用 *p
- 表示取p所保存的地址编号对应的空间内容(指针变量p的解引用)
-
类型
-
自身类型
-
指向类型
- 宽度
- 跨度
-
-
初始化
- NULL
- 局部指针变量不初始化保存随机地址编号
- 初始化为合法空间
-
使用时
- 取地址&
- 取 *
-
注意事项
-
void不能定义变量,void * 可以定义变量
-
void *p
- 不能直接对*p操作
- p强制类型转换后,再*操作
-
-
没有初始化的指针变量不能取*
-
初始化为NULL的指针变量不能取*(更改后可以)
-
不要给指针变量赋普通的数值
-
不要操作越界空间
-
数组单个元素的指针
-
指针变量保存数组首元素的地址
-
p+i :第i个元素的地址
-
[]和*()的关系
- []是*()的缩写
- *(p+i)==p[i]
- 加法的交换律:p[i]==i[p]
-
arr和&arr的区别
- arr首元素的地址,+1跳过一个元素
- &arr首地址,+1跳过整个数组
-
数组名是个符号常量不能被赋值
-
指向同一数组的两个元素的指针
-
相减=相差个数
-
比较大小
- p1、p2比较的是存放的元素的地址
-
指针之间可以赋值
-
不可相加
-
指针数组
- 本质是数组(栈区),数组的每个元素是指针
- int *arr[10]
数组指针
-
本质是一个指针,保存数组首地址
-
要注意
- char (*p3)[5] = &a;√
- char (*p4)[5] = a;×
多级指针
- **p
指针变量作为函数的参数
- 外部变量地址传给函数内部,从而修改外部变量的值
- 一维数组作为函数形参,会被优化成一级指针变量
- 二维数组作为函数形参,会被优化成数组指针 int arr[3][4]-------->int (*p)[4]
- 指针作为函数的返回值,函数不要返回普通局部变量的地址
- 函数名代表的是函数的入口地址
动态内存分配(堆区)
malloc
void *malloc (unsigned int num_size);
-
清空
memset(str ,0,size);
calloc
void *calloc(size_t nmemb , size_t size);
nmemb:申请的块数
size:每一块的大小
realloc
void *realloc(void *s,unsigned int newsize);
在原先s指向的内存基础上重新申请内存,新的内存的大小为 new_size 个 字节,如果原先内存后面有足够大的空间,就追加,如果后边的内存不 够用,则realloc函数会在堆区找一个newsize个字节大小的内存申请,将原先内存中的内容拷贝过来,然后释放原先的内存,最后返回新内存的地址
free
free();
-
防止多次释放
if(p != NULL)
{
free§;
p=NULL;
}
字符串处理函数
str
-
strlen
size_t strlen(const char *s)
返回值为 字符串的长度 不包含’\0’ -
strcpy
char *strcpy( char *dest, const char *src )
-
strncpy
char *strncpy( char *dest, const char *src,int num)
-
若拷贝的位置已经存在字符串,则清空然后拷贝(系统自动清空)
-
-
strcat
char *strcat(char *dest, const char *src);
- strncat
-
strcmp
int strcmp(const char *s1, const char *s2);
- strncmp
-
strchr
char *strchr(const char *s, int c);
从字符串s中查找第一次c字符出现的地址 -
strstr
char *strstr(const char *s1, const char *s2);
从s1中查找字符串s2 返回第一次s2出现的地址
将字符串转为数值
- atoi
- atol
- atof
strtok
char *strtok(char *str, const char *delim);
-
切割代码
while(1) { arr[i] = strtok(arr[i],"😊; if(arr[i] == NULL) break; i++; }
while(arr[i++] = strtok(arr[i],"😊);
子主题 4
sprintf、sscanf
sprintf组包
sscanf解包
-
流指针提取,提取时遇到非要求的就停止
-
使用%*s %*d 跳过提取的内容(不要提取的内容)
-
使用%[n]s %[n]d 提取指定宽度n的字符串或数据
-
%[a-z] 提取a-z的字符串
-
%[aBc] 提取 a B c
-
子主题 6
- %[^abc] 只要不是a b c任何一个 都要
const
修饰变量为只读
const int *p;
- const在的左边 表示 const 修饰的是 而不是 p.
- 效果:用户不能借助*p更改空间的内容 但是 p可以指向其他空间(*p 只读 p可读可写)
int * const p;
- const 在的右边 const修饰的是p 而不是
- 用户可以通过*p 修改p所指向空间的内容 但是 不能再更改p的指向(*p可读可写 p只读)
结构体
初始化
- 类型与结构体内类型一致
清空结构体
- memset(&stu,0,sizeof(stu));
获取
-
逐个获取
scanf("%d %s %d",&lucy.num, lucy.name , &lucy.age);
结构体之间的赋值
-
方式一:逐个成员赋值
- bob.num = lucy.num;
-
方法二:相同类型的结构体变量 可以直接赋值(推荐)
- bob = lucy;
-
方法三:方法二的底层实现
- memcpy(&bob,&lucy,sizeof(struct stu));
结构体数组
结构体指针
结构体的内存对齐
-
确定方法
- 1、确定分配单位:每一行该分配的字节数
- 2、确定成员的起始位置的偏移量==成员的基本类型整数倍
- 3、收尾工作:结构体总大小==分配单位的整数倍
-
结构体嵌套结构体(一定要访问到最底层)
- 1、确定分配单位:每一行该分配的字节数由所有结构体中最大的基本类型决定
- 2、确定成员的起始位置的偏移量成员的基本类型整数倍
结构体成员的偏移量结构体中最大基本类型的整数倍
结构体成员的成员的偏移量==成员的基本类型的整数倍 - 3、收尾工作:结构体总大小分配单位的整数倍
结构体成员的总大小倍嵌套的结构体里面最大基本类型的整数倍
-
强制类型对齐
- #pragma pack (value)
位段(位域)
- 相邻位段可以压缩,但不能超过成员自身大小(多个)
- 位段的赋值不要超过位段的大小,会产生数据的错乱
- 从低位到高位存放
与共用体(union)的区别
-
共用体:
- 所有成员共享一份空间
- 空间大小由最大成员决定
- 注意:数据存放倒着存时候
链表
-
物理存储上非连续,数据元素的逻辑顺序通过链表指针连接次序
-
动态生成每个节点
-
节点包括数据域和指针域
-
链表的插入
-
为插入的节点申请空间
-
判断节点存在
-
不存在,直接赋给头节点
-
存在
-
头部之前插入
- 指针域指向头部,头部指向新的头
-
尾部插入
- 寻找尾节点,尾节点的指针域连接上插入的节点
-
有序插入
- 1、确定插入位置
- 2、判断插入位置
-
-
-
-
-
链表的查询
- 1、判断存在节点
- 2、逐个节点查询
-
链表的删除
-
1、判断存在节点
-
2、节点存在
-
找到删除点
- 头节点
- 中节点
- 尾节点
-
-
-
链表的释放
-
逐个释放
- 头指向下一个节点的位置,再释放此节点
-
-
链表的遍历
-
链表的逆序
- 循环前提:pb保存head->next,将head->next置NULL
- 1、pr保存pb->next,原因:pb->next会指向head
- 2、pb->next 指向 head,原因:逆转方向
- 3、保存 逆转方向的代码 可以重复 执行
-
双向链表
- 双向循环链表
深拷贝和浅拷贝
-
指针作为结构体的成员
-
操作前,必须有合法的空间(ralloc)
- 指向堆区空间的话,一定要释放
-
-
浅拷贝
- 只申请一次堆区空间,释放两次出问题
-
深拷贝
- 为每个结构体指针变量申请独立的堆区空间,释放不会出错
文件
缓冲区:提高存取效率,延长磁盘使用寿命
磁盘文件分类
-
物理:都是二进制存储,顺序存储
-
逻辑:
-
文本文件:字符编码
- 译码容易
- 占用空间大
-
二进制文件:值编码
- 空间利用率高
- 特殊的解码器
-
文件指针:FILE *fp
fp=fopen(文件名,文件使用方式);
-
r
-
rb
- 不创建
-
-
w
- 不存在,创建;存在,清空,再操作;
-
a
- 不存在,创建;存在,文件结尾处操作
-
-
可读可写
-
r+
- 不创建
-
w+
- 创建
-
a+
- 创建,添加
-
-
-
b
- 二进制方式打开
-
t
- 文本打开(省略)
fclose(文件指针)
- 关闭成功,返回0
文件读写
-
字节读写
- fgetc(fp);
- fputc(ch,fp);
-
字符串读写
-
fgets(str,n,fp);
- n:字符数,要获取n-1个字符
-
fputs(字符串,fp);
-
-
块读写
- fread(buffer,size,count,fp);
- fwrite(buffer,size,count,fp);
-
格式化操作
-
fprintf(文件指针,格式字符串,输出表列);
fprintf(fp,“英雄:%s 防御:%d 攻击:%d\n”,hero[i].name, hero[i].deff,hero[i].atk);
-
fscanf(文件指针,格式字符串,输出表列);
-
-
复位文件流指针
- rewind(文件指针);
-
获取文件长度
- long=ftell(文件指针);
-
文件流指针定位
- fseek(文件指针,位移量,起始点);
-
feof():判断文件是否到达文件末尾
排序方式
冒泡排序
//排序
for(i=0;iarr[j+1])
{
int flag = 0;
for(j=0;j<n-1-i;j++)
{
int tmp = 0;
tmp = arr[j];
arr[j]=arr[j+1];
arr[j+1]=tmp;
flag = 1;
}
if(flag == 0)//数组已经有序
break;
}
- 相邻比较,大下沉,小上升
- 在外层循环和内层循环之间加一个初始化的变量,在内层循环给它赋值,可以判断出是否进行了内层循环,从而达到减少循环次数的目的
- 最先确定位置的是最后一位,逐渐向前确定
选择排序
- 每次外循环只进行一次交换
- 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置(末尾位置),然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕