C语言基础
C语言基础
day01
C语言特点
优点
代码量小
执行速度快
功能强大
编程自由
缺点
写代码实现周期长
可移植性较差
过于自由,经验不足出错
平台库依赖多
计算机结构组成
计算机系统组成
C语言关键字
9种控制语句
运算符
#include <stdio.h> // 关键标识符,表示引入头文件,include
// stdio.h 系统标准输入,输出库对应的头文件,给printf服务
// <> 使用系统库函数 ""用户自定义库函数
//int 函数返回值是整形数据 main:函数名,程序唯一入口,必须有只写一次
int mian(void) // void函数调用不需要传参
{ //函数体:起始位置
printf("hello world\n");
system("pause")
return 0; //返回当前函数--退出程序
} //结束为止
解决提示窗一闪而过
用system函数解决
在return 0 之前,添加system(“pause”) 函数调用
借助vs工具解决
在项目上 -- 属性--配置属性--连接器--系统---子系统--下拉框中控制台
两种编写helloworld方式
1.借助vs工具编写
借助记事本,gcc编译工具
gcc环境变量的配置
使用记事本创建hellworld.c文件 在里面写程序
gcc编译工具 ,执行 gcc helloworld.c -o hello.exe
在终端中运行,hello.exe
注释
单行注释 //
多行注释 /* */
system 函数
执行系统命令
system(“cmd”)
清屏 cls
gcc编译四步骤
gcc - E hello.c -o hello.i
预处理 -E xxx.i 预处理文件
1. 头文件展开,不检查语法错误,可以展开任何文件
1. 宏定义替换 :将宏名替换为宏值
3. 替换注释 : 变成空行
4. 展开条件注释 : 根据条件展开指令
-
#include <stdio.h> #define PI 3.14 int main(void) { printf("%d\n", PI); return 0; }
编译 -S hello.s 汇编文件
1. 将c程序翻译成汇编指令
2. 逐行检查语法错误 ,编译4步骤最耗时的过程
汇编 -c hello.o 目标文件
gcc -c hello.s -o hello.o
翻译将汇编指令翻译成对应的二进制代码
链接 hello.exe 可执行文件
-
数据段合并
-
数据地址回填
-
库引入
C语言可以嵌入汇编
代码调试
打开调试F5,调试 F11
监视,监视变量名的变化
VS快捷键
day02
常量与变量
常量:不会变化的量
-
”A”,”hello”,“10”,”1.234567”,””
-
define PI 3.1415 定义宏 名+值
-
const int a = 10; const 关键字修饰的变量,表示只读变量
#include <stdio.h>
#define PI 3.145
int main(void)
{
int r = 3;
float s = PI * r * r;
float l = 2 * PI * r;
//printf("圆的周长%f\n",l);
//printf("圆的面积%f\n",s);
printf("圆的周长%.2f\n", l); // 保留小数点后两位
printf("圆的面积%.2f\n", s);
return 0;
}
const int a = 10 定义语法 const类型名 变量名 = 变量值
变量的定义语法
变量三要素 :类型名,变量名 ,变量值
float a = PI * r* r 变量值是表达式
变量的声明:
1. int a; 没有变量值的变量定义
1. extern int a; 添加了关键字
1. 变量定义会开辟内存空间,变量声明不会开辟内存空间
1. 当编译器编译程序时,在变量使用之前,如果没有看到变量定义,编译器会自动寻找一个变量声明提升为定义,如果该变量声明有extern 关键字,无法提升
1. 定义变量时,尽量不要重名
1.
标识符,变量和常量的统一
命名规则:
1. 通常常量使用大写,变量使用小写,大小写严格区分
2. 只能使用,字母数字下划线 命名标识符,数字不能开头,
1. int a5ir = 10;
2. int _34f = 6
3. float a2_i85c 5.4
3. 禁止使用关键字,系统函数做标识符
整型变量定义输出
格式
%d 输出一个有符号10进制的int类型
%x 输出8进制int类型
%X 16进制int类型 字幕以小写输出
%u输出10进制无符号数
有符号整型
signed:有符号 ,不常用
- int 类型 4字节 %d
- int 名 = 值
- int a = 40;
- short 类型 2字节 %hd
- short 名 = 值
- long 类型 4字节 %ld win 32/64 linux 32:4,64:8
- long 名 = 值
- long long 类型 %lld 8字节
- long long 名 = 值
无符号整型
unsigned :无符号 只表示数据量,而没有方向
int 名 = 值
- int 类型 4字节 %u
- unsigned int 名 = 值
- unsigned int a = 40;
- short 类型 2字节 %hu
- unsigned short 名 = 值
- long 类型 4字节 %lu
- unsigned long 名 = 值
- long long 类型 8字节 %llu
- unsigned long long 名 = 值
定义常量
define N 1024
sizeof 关键字
不是函数,用来求一个变量类型的大小,返回一个无符号整数使用%u,接收返回值
方法1 sizeof (类型名)
sizeof (变量名)
char字符类型
存储一个字符
‘a’,A%,#0
格式匹配符
%c
字符ASCLL码 (记忆 )
‘A’:65
‘a’ 97
‘0’ 48
‘\n’ 10
‘\0’ 0
转义字符 ‘\’ 将普通字符转为特殊,反之
转义字符表
实型
float 单精度 4字节
%f 使用格式符 ,默认保留6位
float v1 = 1.22
double 双精度 8字节 默认是双精度
float v2 = 3.456
unsigned float 无符号的浮点型
unsigned double 无符号的浮点型
printf("m = %5.2f\n",m); 输出含义是 :显示5位数(包含小数点),不足8位用0填充,并且保留3位小数,对第4位四舍五入
输出格式匹配符
对于单精度数,使用 %f 格式符输出时,仅前7位是有效数字,小数6位。
对于双精度数,使用 %lf 格式符输出时,前16位是有效数字,小数6位。
格式字符:指定输出项的数据类型和输出格式。
d 有符号十进制整数。
o 无符号八进制数。
x 无符号十六进制数。(小写的x格式中用小写字母a,b,c,d,e,f来表示10到15之间的数,大写的X则
c 输出一个字符。
s 输出一个字符串。
e 以指数形式输出实型数。
f 以小数形式输出实型数。
g 自动决定输出格式为e和f中较短的一种,不打印无效的零。
% 输出%。
- %d %u %o %x
- %hd %hu
- %ld %lu
- %lld % llu
- %c %f %lf
进制和转换:
十进制转2进制。 --- 除2反向取余法。 【重点】
十进制转8进制。 --- 除8反向取余法。
十进制转16进制。--- 除16反向取余法。
int a = 56; -- 111000
int b = 173; -- 10101101
2进制转10进制。
2^10 = 1024
2^9 = 512
2^8 = 256
2^7 = 128
2^6 = 64
2^5 = 32
2^4 = 16
2^3 = 8
2^2 = 4
8进制:
8进制转10进制。
定义8进制数语法:
056: 零开头,每位数0~7之间。 ---- 46
0124: ---- 84
8进制转2进制。
按421码将每个八进制位展开。
056:5--》 101。 6--》 110 。
101110
05326:5 --》 101。 3--》 011。 2--》 010。 6--》 110
2进制转8进制:
1 010 111 010 110: 012726
自右向左,每3位一组,按421码转换。高位不足三位补0
16进制:
语法: 以0x开头,每位 取 0-9/A-F/a-f
A -- 10
B -- 11
C -- 12
D -- 13
E -- 14
F -- 15
16 -- 10:
0x1A: 16+10 = 26
0x13F:15+3x16+256
16 -- 2:
0x1A: 00011010
0x13F: 000100111111
2 -- 16:
0001 0011 1111: 13F
自右向左,每4位一组,按8421码转换。高位不足三位补0
总结:
int m = 0x15F4;
int n = 345;
int var = 010011; // 不允许。 不能给变量直接复制 二进制数据。
输出格式:
%d %u %o %x %hd %hu %ld %lu %lld %llu %c %f %lf
%d %u %x %c %s
存储知识:
1 bit位 就是一个 二进制位
一个字节 1B = 8bit位。
1KB = 1024B
1MB = 1024KB
1GB = 1024MB
1TB = 1024GB
源码反码补码:【了解】
源码:
43 -> 00101011
-43 --> 10101011
反码:
43 -> 00101011
-43 --> 10101011
11010100
补码:(现今计算机采用的存储形式)
43 -> 00101011 : 正数不变
-43 --> 11010101 : 负数,最高位表符号位, 其余取反+1
43-27 ==》 43 + -27
人为规定: 10000000 --》 -128
char 类型:1字节 8个bit位。 数值位有7个。
有符号: -2^7 --- 2^7-1 == -2^(8-1) -- 2(8-1) -1
--》 -128 ~ 127
无符号: 0 ~ 2^8 -1
--》 0~255
不要超出该数据类型的存储范围。
short类型:2字节 16bit
有符号: -2^15 --- 2^15-1 == -2^(16-1) -- 2(16-1) -1
--》 -32768 ~ 32767
无符号: 0 ~ 2^8 -1
--》 0~65535
int 类型:4字节 -2^(32-1) -- 2^(32-1)-1
有符号:
--》 -2147483648 ~ 2147483647
无符号: 0~2^32 -1
--》 0~4294967295
long类型:4字节
有符号:
--》 -2147483648 ~ 2147483647
无符号: 0~2^32 -1
--》 0~4294967295
longlong 类型:8字节
有符号:
--》 -2^(63) ~ 2^(63)-1
无符号:
--》 0~2^63-1
day03
类型限定符
extern: 表示声明,没有内存空间,不能提升
const: 限定一个常量,常量的值不能修改
volatile 防止编译器优化代码
register 定义寄存器变量,提高效率,register是建议性指令而不是命令指令,如果cpu是空闲寄存器那么register无效
字符 char ch = ‘A’ 一个字节
字符串 “abdh” 双引号引着字符串,一定有一个结束标记“\0”
printf() %s 挨着从字符串第一个字符开始打印,打印到‘\0’结束
‘a’ 不等于 “a”
printf()函数
%s 打印字符串
%d 打印整数
%c 打印字符
%x 打印16进制数
%u 打印无符号
%m. n 打印实型,一共有m位 (整数小数,小数点,n位小数)
%0m. nf 不足n位前面补0
%% 显示一个% 转移字符对%无效
%Ns 显示N个字符的字符串,不足用空格向左填充
puchar()函数
可以直接输出ASCII码
不能输出字符串
‘abc’ 既不是有效字符,也不是有效字符串
scanf 函数
从键盘接受用户输入
接收整数
%d
int a,b,c 创建变量空间 等待接收用户输入
接收字符%c
char a,b,c
scanf_s(“%c%c%c”,&a,&b,&c)
接收字符串 %s
char str[] = “”;
char str[]; 定义一个数组,用来接收用户输入的字符串
scanf(%s,str); //变量名要取地址传给scanf 数组名本身表示地址,不用&
为了防止数据溢出,scanf_s应该用以下形式,抛弃scanf函数
scanf具有安全隐患,数据能存储但是不被保护【空间不足不要使用】
scanf函数接收字符串,碰到空格和换行自动终止,不能使用csanf接收带有空格的字符串
scanf_s("%c,%c",&a,1,&b,1);
getchar()函数
从键盘用户输入获取一个字符
打印换行常用putchar(“\n”)
算术运算
除0错误
对0取余错误操作
除法运算得到的结果赋值给整型变量取整数部分
++ --
前缀自增
int a = 10;
++a;
先自增,再取值
后缀自增
int a = 10
a++;
先取值,再自增
小数不能取余
10%-3 = 1
-10%%-3 = -1
int a = 10;
printf("a=%d\n", a++);
printf("a=%d\n", a);
printf("a=%d\n", ++a);
printf("a=%d\n", a);
printf("a=%d\n", a--);
printf("a=%d\n", a);
printf("a=%d\n", --a);
printf("a=%d\n", a);
赋值运算符
int a = 5;
a +=10’
a-=30;
a%=5
比较运算
== 判断是否相等
!= 不等于
≠
<=
=
逻辑运算
运算符优先级
后缀自增高于前缀
sizeof>算术运算>比较运算>逻辑运算>三目运算(条件运算)>赋值运算符>逗号运
三目运算
表达式1 ? 表达式2:表达式3
表达式1是以一个判别表达式,
如果为真,整个三目运算,取值表达式2
如果为假,三目运算取值表达式3
类型转换
由编译器自动完成
由赋值产生的类型转换
隐式类型转换
int r = 3
float s = 3.14 * r * r
由赋值产生的类型转换 ,小转大没问题,大转小可能发生数据丢失
强制目标类型
(目标类型)带转换变量
(目标类型)带转换表达式
大多数用于函数调用期间,实参给形参传值
分支语句
if 语句 匹配一个范围,属于模糊匹配
if(判别表达式){
判别表达式为真,执行代码
}
else{
}
/*int p1, p2, p3;
printf("输入三只猪的体重");
scanf_s("%d %d %d",&p1 ,&p2,&p3);
if (p1>p2)
{
if (p1>p3)
{
printf("第一只猪最重%d\n",p1);
}
else
{
printf("第三只猪最重%d\n", p3);
}
}
else
{
if (p2>p3)
{
printf("第二只猪最重%d\n", p2);
}
else
{
printf("第三只猪最重%d\n", p3);
}
}*/
switch 分支 精确匹配
switch(判别表达式)
{
case 1:
执行语句1
break
case 2:
执行语句2
break //防止case穿透
….
default
}
/*int score;
scanf_s("%d",&score);
switch (score/10)
{
case 10:
printf("优秀\n");
break;
case 8:
printf("良\n");
break;
case 7:
printf("良\n");
break;
case 6:
printf("及格\n");
break;
default:
printf("不及格\n");
break;
}*/
case穿透
在一个case分支中,如果没有break,那么它会向下继续执行下一个case分支
while循环
while(条件判别表达式)
{
循环体
}
/*int num = 1;
while (num<=100)
{
if ( num%7==0 || num%10==7 || num/10==7 )
{
printf("敲桌子\n");
}
else
{
printf("%d\n",num);
}
num++;
}*/
do while 循环
无论如何先执行循环体一次,然后、再判断是否继续循环
do{
循环体
}while(条件判断表达式);
int a = 1;
do
{
++a;
printf("a=%d\n",a);
} while (a<10);
练习:求水仙花数
int num = 100;
int a, b, c;
do
{
a = num % 10;
b = num / 10 % 10;
c = num / 100;
if (a*a*a + b*b*b+ c*c*c == num)
{
printf("%d\n",num);
}
num++;
} while (num<1000);
day04
for 循环
for (表达式1,表达式2)
{
循环体
}
表达式--表达式2(判别表达式)--真--循环体--表达式3(判别表达式---)
循环因子:
定义在for之外,for循环结束,也能使用
定义在for之内,for循环结束,不能使用
3个表达式,可变换省略,两个分号不能省
#include<stdio.h>
int main(void)
{
/*int i = 0;
int sum = 0;
for (size_t i = 0; i < 100; i++)
{
sum = sum + i;
}
printf("sum= %d\n",sum);*/
/*int i = 0;
int sum = 0;
for ( ; i <=100; )
{
sum = sum + i;
i++;
}
printf("sum= %d\n",sum);*/
/*int i = 0;
int sum = 0;
for ( ; ; )
{
printf("i = %d\n",i);
i++;
}
printf("sum= %d\n",sum);*/
int i = 0;
int sum = 0;
int a = 0;
for (i=1,a=3 ;i<10,a<20;i++,a+=5 )
{
printf("i = %d\n", i);
printf("a = %d\n", a);
}
}
猜数字游戏
生成一个随机数
添加一个随机数种子 ,srand(time(NULL))
添加头文件<stido.h> <time.h>
生成随机数 int n = rand()%100 0-99
循环输入数据
while()
{
接收用户输入 scanf(“%d”,&num);
比较用户数和随机生成大小;
if (n>num)
else{}
}
跳出循环
break,跳出一重循环
break,作用
-
跳出一重循环
-
防止case 穿透
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
int main(void)
{
srand(time(NULL));
int n = 0;
int num = rand() % 100;
for (;;)
{
scanf_s("%d", &n);
if (n < num)
{
printf("猜小了\n");
}
else if (n > num)
{
printf("猜大了\n");
}
else
{
printf("猜中了");
}
}
}
嵌套循环
for(i=0,i<10,i++)
{
for(j=0,j<10,j++)
{
循环体
}
}
模拟电子表打印
#include<stdlib.h>
#include<time.h>
#include<stdio.h>
#include<math.h>
int main(void)
{
int i, j, k;
for (size_t i = 0; i < 24; i++)
{
for (size_t j = 0; j < 60; j++)
{
for (size_t k = 0; k < 60; k++)
{
printf("%02d:%02d:%02d\n",i,j,k);
Sleep(1000);
system("cls");
}
}
}
}
打印99乘法表
#include<stdlib.h>
#include<time.h>
#include<stdio.h>
#include<math.h>
int main()
{
for (size_t i = 1; i <= 9; i++)
{
for (size_t j = 1; j <= i; j++)
{
printf("%dx%d=%d", j, i, j * i); printf(" ");
}
printf("\n"); putchar('\n');
}
}
continue
作用结束本次循环,之后的循环体不执行,本次循环
#include<stdlib.h>
#include<time.h>
#include<stdio.h>
#include<math.h>
int main(void)
{
/*for (size_t i = 0; i < 5; i++)
{
printf("i = %d\n",i);
if (i==3)
{
continue;
}
printf("=======1========\n");
printf("=======2========\n");
printf("=======3========\n");
}*/
int num = 5;
while (num-- !=0)
{
printf("num = %d\n", num);
if (num ==3)
{
continue;
}
printf("=======1========\n");
printf("=======2========\n");
printf("=======3========\n");
}
}
goto
设定一个标签
使用goto跳转到标签位置,只在函数内部使用
一般不推荐使用
数组
相同数据类型有序集合
int a = 10;
int arr[10] = [1,2,3,4,5,6,7,8,9,0]
int arr[10] = [1,2,3,4,5,6,7,8] 剩余未初始化的元素
int arr[10] = {0} 初始化一个全为0的数组
int arr[] = {1,2,3,4,5} 编译器自动求取元素个数
int arr[] = {0} 只有一个元素,值是0
int arr[10]
arr[0] = 5;
arr[1]=6;
arr[2]=7; 其余元素未被初始化,默认随机数
数组名地址,是数组首元素地址,arr=&arr[0]
数组操作
#include<stdlib.h>
#include<time.h>
#include<stdio.h>
#include<math.h>
int main(void)
{
int a = 5, b = 10, c = 10;
int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
printf("&arr[0]=%x\n",&arr[0]); //取数组首元素的地址
printf("&arr[1]=%p\n",&arr[1]);
// x,和p的区别就是 p会用0补全前面的空位
printf("&a=%p\n",&a);
printf("&b=%p\n",&b);
printf("&c=%p\n",&c);
printf("arr=%p\n",arr); //数组名
printf("数组大小%u\n", sizeof(arr));
printf("数组元素大小 %u\n",sizeof(arr[0]));
printf("数组元素个数 %d\n",sizeof(arr)/sizeof(arr[0]));
}
数组逆序
#include<stdlib.h>
#include<time.h>
#include<stdio.h>
#include<math.h>
int main(void)
{
int arr[] = { 1,2,3,4,5,6,7,8 };
int i = 0;
int len = sizeof(arr) / sizeof(arr[0]); // 数组元素个数
int j =len-1; //表示数组最后一个元素下表
int temp = 0; // 临时变量
for (size_t m = 0; m <len ; m++)
{
printf("%d",arr[m]);
}
printf("\n");
while (i<j)
{
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
i++;
j--;
}
for (size_t n = 0; n < len; n++)
{
printf("%d", arr[n]);
}
printf("\n");
}
冒泡排序
#include<stdlib.h>
#include<time.h>
#include<stdio.h>
#include<math.h>
int main(void)
{
int acc[] = { 1,45,6,4,7,89,10,13 };
int n = sizeof(acc)/sizeof(acc[0]);
int temp = 0;
for (size_t i = 0; i < n-1; i++)
{
for (size_t j = 0; j < n-1-i; j++)
{
if (acc[j]>acc[j+1])
{
temp = acc[j];
acc[j] = acc[j + 1];
acc[j + 1] = temp;
}
}
}
for (size_t q = 0; q < n; q++)
{
printf("%d", acc[q]); printf(" ");
}
printf("\n");
}
外层循环一行,内层循环一列
day05
二维数组
int arr[10] = {1,2,3,4,5,6,7};
定义 int arr[2] [3] ={
{1,2,3},
{4,5,6}
} ;
int arr[3][5] = {{2, 3, 54, 56, 7 }, {2, 67, 4, 35, 9}, {1, 4, 16, 3, 78}};
打印
for
for(i = 0; i < 3; i++) // 行
{
for(j = 0; j <5; j++) // 列
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
大小:
数组大小: sizeof(arr);
一行大小: sizeof(arr[0]): 二维数组的一行,就是一个一维数组。
一个元素大小:sizeof(arr[0][0]) 单位:字节
行数:row = sizeof(arr)/ sizeof(arr[0])
列数:col = sizeof(arr[0])/ sizeof(arr[0][0])
地址合一:
printf("%p\n", arr); == printf("%p\n", &arr[0][0]); == printf("%p\n", arr[0]);
数组的首地址 == 数组的首元素地址 == 数组的首行地址。
二维数组初始化
-
常规初始化
int arr[3] [5] = {{2, 3, 54, 56, 7 }, {2, 67, 4, 35, 9}, {1, 4, 16, 3, 78}};
-
不完全初始化
int arr[3] [5] = {{2, 3}, {2, 67, 4, }, {1, 4, 16, 78}}; 未被初始化的数值为 0
int arr[3][5] = {0}; 初始化一个 初值全为0的二维数组
int arr[3][5] = {2, 3, 2, 67, 4, 1, 4, 16, 78}; 【少见】 系统自动分配行列 -
不完全指定行列初始化
-
int arr[][] = {1, 3, 4, 6, 7}; 二维数组定义必须指定列值。 int arr[][2] = { 1, 3, 4, 6, 7 }; 可以不指定行值。
二维数组求学生功课成绩
#include<stdlib.h>
#include<time.h>
#include<stdio.h>
#include<math.h>
int main(void)
{
int scores[5][3] = { 1,2,3,4,5,6,7,8,9 };
int row = sizeof(scores) / sizeof(scores[0]);
int col = sizeof(scores[0]) / sizeof(scores[0][0]);
//获取5名学生,3门课的成绩
for (size_t i = 0; i < row; i++)
{
for (size_t j = 0; j < col; j++)
{
scanf_s("%d",&scores[i][j]);
}
}
// 求一个学生总成绩
for (size_t i = 0; i < row; i++)
{
int sum = 0;
for (size_t j = 0; j < col; j++)
{
sum += scores[i][j];
}
printf("第%d个学生总成绩, %d\n",i+1,sum);
}
// 求一门功课总成绩
for (size_t i = 0; i < col; i++)
{
int sum = 0;
for (size_t j = 0; j < row; j++)
{
sum += scores[j][i];
}
printf("第%d门功课总成绩: %d\n",i+1,sum);
}
}
快捷导入代码
VS使用技巧-使用代码片段管理器
VS中提供了输入指定代码片段的快捷操作,如下图,在编辑区中输入if
,会弹出提示,如果按TAB或Enter键,会自动将代码补成
if(true)
{
}
如果程序中需要重复输入大段或常用的代码片段,可使用代码片段管理器自定义代码片段及相应的快捷键,操作步骤如下:
- 在VS中依次选择:菜单栏→工具→代码片段管理器(或者使用快捷键Ctrl+K,Ctrl+B),代开代码片段管理器;
语言选择自己使用的编程语言,此处选择“Visual C++”,展开下方的Visual C++结构,可以看到VS内部预先定义好的代码片段及说明,位置一行显示了代码片段的所在的路径;
打开代码片段所在的路径,打开“if.snippet”,说明如下:
参考上述内容定义自己的代码片段:
<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>cli</Title>
<Shortcut>cli</Shortcut>
<Description>btn_clicked 语句的代码片段</Description>
<Author>zx</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>expression</ID>
<ToolTip>按钮名称</ToolTip>
<Default></Default>
</Literal>
</Declarations>
<Code Language="cpp"><![CDATA[void on_$expression$_clicked();]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
按下述步骤将自定义的文件添加到代码片段管理器中
- 此时在VS编辑器中输入
cli
,按TAB或Enter键,即会自动生成自定义的代码片段;
- 如果要删除自定义的代码片段,需到指定的位置删除文件。
多维数组
三维数组 [][][层] [行] [列]
数组类型 数组名 [层] [行] [列]
int arr[2] [3] [4];
{
一层
{
{}, 1行
{}, 2行
{}, 3行
{} 4行
},
二层
{
{},
{},
{},
{}
},
三层
{
{},
{},
{},
{}
}
}
字符与字符串
字符串中字幕出现的次数
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
int main(void)
{
/*char str[6] = {'h','e','l','l','l','\0'};
char str2[] = "world";
printf("%s\n",str);
printf("%s\n",str2);*/
/*char str[11] = { 0 };
for (size_t i = 0; i < 10; i++)
{
scanf_s("%c",&str[i]);
}
for (size_t i = 0; i < 10; i++)
{
printf("%c",str[i]);*/
//}
char str[11] = { 0 }; // helloworld --> 26个英文字母 a-z a:97 d:100
// scanf("%s", str);
for (size_t i = 0; i < 10; i++)
{
scanf("%c", &str[i]);
}
int count[26] = { 0 }; // 代表26个英文字母出现的次数。
for (size_t i = 0; i < 11; i++)
{
int index = str[i] - 'a'; // 用户输入的字符在 count数组中的下标值。
count[index]++;
}
for (size_t i = 0; i < 26; i++)
{
if (count[i] != 0)
{
printf("%c字符在字符串中出现 %d 次\n", i + 'a', count[i]);
}
}
system("pause");
return EXIT_SUCCESS;
}
字符串scanf
用于存储字符串空间必须足够大,方知衣橱
获取字符串 %s,遇到空格和\n终止
借助正则表达式,或取带有空格字符串:scanf(“%[ ^\n]”,str)
字符串操作函数
gets 获取一个字符串,返回字符串首地址
chargets(chars)
参数用来存储字符串空间
返回值
字符串操作函数
gets
从键盘获取一个字符串,返回字符串的首地址,可以获取带有空格的字符串,不是俺去眼都
chargets(chars)
参数,用来存储字符串的空间地址
返回值,返回实际获取到的字符串首地址
fgets
从stdin获取一个字符串,预留\0存储空间,空间足够读\n,空间不足舍弃
char *fgets(char *s, int size, FILE *stream);
参数1,用来存储字符串的空间地址
参数2,描述空间大小
参数3,读取字符串位置,键盘 --》 标准输入:stdin
返回值:返回实际获取到的字符串首地址。
puts
puts*fgets(“%s”,”heloo”); / printf("hello\n"); / puts("hello"); 输出字符串后会自动添加 \n 换行符。
参数一,等待写处屏幕中央的字符串
返回值:成功,非负数0,失败
fputs,
将一个字符串写到stout输出字符串,不添加\n换行符
int fputs(const charstr,FILEstreamm)
参数1,等待写出屏幕的字符串屏幕-标准输出stdout
参数:写出位置 stdout
返回值 :成功1,失败-1
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
int main(void)
{
// gets
/*char str[11];
printf("获取字符串: %s\n",gets(str));*/
//fgets
/*char str[10];
printf("获取字符串:%s\n",fgets(str,sizeof(str),stdin));*/
//puts
/*char str[]= "hello world\n";
int ret = puts(str);
printf("ret = %d\n",ret);*/
// fputs
//char str[] = "hello world";
////int ret = fputs(str,stdout);
//int ret = fputs("hello world",stdout);
//printf("ret = %d\n", ret);
system("pause");
return EXIT_SUCCESS;
}
strlen
strlen: 碰到 \0 结束。
size_t strlen(const char *s);
参1: 待求长度的字符串
返回:有效的字符个数。
字符串拼接
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
int main13(void)
{
char str1[] = "hello";
char str2[] = "world";
char str3[100] = { 0 };
int i = 0;
while (str1[i] != '\0') //循环sttr1
{
str3[i] = str1[i];
i++;
}
int j = 0;
while (str2[j]) //循环str2
{
str3[i + j] = str2[j];
j++;
}
str3[i + j] = '\0';//手动添加结束标记
printf("str3=%s\n",str3);
system("pause");
return EXIT_SUCCESS;
}
函数
- 提高代码复用率
- 提高程序模块化
分类
1. 系统库函数,标准C库 libc
1. 引入头文件
2. 根据函数原型调用
2. 用户自定义
1. 除了需要提高函数原型之外,haunt需要提供函数原型实现
随机数
1. 播种随机数种子 srand(time(NULL))
2. 引入头文件 #include <stdlib.h> <time.h>
3. 生成随机数 rand()
函数定义
-
包含函数原型(返回值类型,函数名,形参)函数体(大括号,代码实现)
-
形参列表,形式参数列表,一定包含,类型名,形参名
-
int add(int a,int b,int c)
{
return a+b+c
}
函数调用
- 包含函数名(实参列表)
- ret = add (10,4,28)
- 实参,调用时。传参必须按照严格形参填充,(参数个数类型顺序)
函数声明
- 函数调用之前,编译必须见过函数定义,否则,需要函数声明
- 包函原型(返回值类型,函数名,形参列表)
- 隐式声明,不要依赖
- 默认编译器做隐式声明函数时,返回都是int,根据调用语句不全函数名和形参列表
-
include <>包函函数声明
exit函数 #include <stdlib.h>
return 关键字,返回当前函数调用,将返回值返回给调用者
exit() 退出当前程序
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
//函数声明
void bubble_sort(int arr[]);
void print_arr(int arr[]);
int main(void)
{
printf("add=%d\n",add(2,6));
int arr[] = {1,4,34,656,7,8,12,34,32,65,78};
bubble_sort(arr);
print_arr(arr);
system("pause");
return EXIT_SUCCESS;
}
void print_arr(int arr[])
{
for (size_t i = 0; i < 10; i++)
{
printf("%d ",arr[i]);
}
}
void bubble_sort(int arr[])
{
int i, j, temp;
for (size_t i = 0; i < 10-1; i++)
{
for (size_t j = 0; j < 10-1-i; j++)
{
if (arr[j]>arr[j+1])
{
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
int add(int a, int b)
{
return a + b;
}
多文件联编
将多个含有不同函数功能 .c 文件模块,编译到一起,生成一个 .exe文件。
<>包裹的头文件为系统库头文件。
""包裹的头文件为用户自定义头文件。
防止头文件重复包含:头文件守卫。
1) #pragma once --- windows中
2) #ifndef __HEAD_H__ <--- head.h
#define __HEAD_H__
.... 头文件内容
#endif
头文件
#ifndef __HEAD_H_
#define __HEAD_H_
//头文件
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
// 函数声明
int add(int a,int b);
int sub(int a,int b);
int mul(int a,int b);
#define N 10
#define PI 3.14
#endif // !__HEAD_H_
函数调用
#define _CRT_SECURE_NO_WARNINGS
#include "head.h"
int main(void)
{
int a = 5;
int b = 6;
printf("%d+%d=%d\n",a,b,add(a,b));
printf("%d-%d=%d\n",a,b,sub(a,b));
printf("%dx%d=%d\n",a,b,mul(a,b));
system("pause");
return EXIT_SUCCESS;
}
函数
int add(int a, int b)
{
return a + b;
}
int mul(int a, int b)
{
return a *b;
}
int sub(int a, int b)
{
return a - b;
}
指针与内存单元
指针
内存单元:计算机内存最小的存储单位,内存单元,每一个内存单元都有唯一的一个编号,叫这个内存单元编号是“地址”
指针变量:存地址变量
指针定义和使用
int a = 10;
int *p = &a
*p = 250 指针的解引用,间接引用
*p 将p变量的内容取出,当成地址看待,找到改地址对应的空间
如果做左值,存数据到空间
如果做右值,取出空间中的内容
任意指针类型大小
指针大小与类型无关,只和当前使用的平台架构有关,,32位:4字节,,64位:8字节
野指针
-
没有一个有效地址空间指针
-
int *p
-
*p = 1000;
-
p 是一个值,但是不是可访问的内存区域
-
int *p = 10
-
*p = 2000;
-
杜绝野指针
-
//野指针 /*int *p; *p = 2000; printf("*p = %d\n",*p);*/ /*int m; int* p = 1000; p = &m; *p = 2000; printf("*p = %d\n",*p);*/
空指针
//空指针
int* p = NULL;
if (p !=NULL)
{
*p = 300;
printf("*p = %d\n",*p);
}
泛型指针
可以接收任意一种变量地址,但是,在使用必须借助,强转类型具体化类型
char ch = “R”;
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
int main0301(void)
{
int a = 345;
char ch = 'R';
void *p; // 万能指针、泛型指针
//p = &a;
p = &ch;
printf("%c\n", *(char *)p);
system("pause");
return EXIT_SUCCESS;
}
指针与数组
数组名
数组名是地址常量,不可以被赋值,++ / -- / += / -= / %= / /= 带有副作用的运算符
指针是变量,可以用数组名给指针赋值
取数组元素:
-
int arr[] =
-
int *p = arr;
-
arr[i] == *(arr+0) == p[0] == *(p+0)
指针与数组区别
- 指针是变量,数组名是常量
- sizeof(指针) 4字节/8字节
- sizeof(数组)数组实际字节数
指针++ 操作数组
int arr[] = { 1, 2, 4, 5, 6, 7, 8, 9, 0 };
int *p = arr;
for (size_t i = 0; i < n; i++)
{
printf("%d ", *p);
p++; // p = p+1; 一次加过一个int大小。 一个元素。
}
p的值随着循环不断变化,打印结束后,p指向一块无效的地址空间(野指针)
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
int main0401(void)
{
int a[] = { 1,2,3,4,5,6,6,7,8,9 };
int n = sizeof(a) / sizeof(a[0]);
int* p = a;
printf("sizeof(a) = %u\n",sizeof(a));
printf("sizeof(p) = %u\n",sizeof(p));
for (size_t i = 0; i < n; i++)
{
printf("%d\n",*(a+i)); // a[i] = *(a+i)
printf("%d\n",a[i]);
printf("%d\n",p[i]);
printf("%d\n",*(p+i)); // p[i] = *(p+i)
}
system("pause");
return EXIT_SUCCESS;
}
// 指针 +操作数组元素
int main0402(void)
{
int arr[] = {1,2,3,4,5,6,7,8,9,0};
int *p = arr;
int n = sizeof(arr) / sizeof(arr[0]);
printf("firstt p = %p\n",p);
for (size_t i = 0; i < n; i++)
{
printf("%d",*p);
p++;
}
printf("last p=%p\n",p);
}
int main(void)
{
int arr[10];
int n = sizeof(arr) / sizeof(arr[0]);
int* p = arr;
for (size_t i = 0; i < n; i++)
{
*(p + i) = 10 + i;
}
for (size_t i = 0; i < n; i++)
{
printf("%d ",*p);
p++;
}
}
修饰指针
const int *p
可以修改p,不可以修改*p
int const *p
可以修改p,不可以修改*p
int *const p
可以修改 *p
不可以修改 p
const int *const p
不可以修改 p,不可以修改 *p
总结:const 向右修饰,被修饰部分即为只读
常用:在函数形参内,用来限制指针所对应的内存空间为只读
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
int main(void)
{
//修饰变量
//const int a = 20;
//int* p = &a;
//*p = 650;
//printf("%d\n",a);
// const int *p
/*int a = 10;
int b = 30;
const int* p = &a;
p = &b;*/
/*int a = 10;
int b = 30;
int const* p = &a;
p = &b*/
/*int a = 10;
int b = 10;
int* const p = &a;
*p = 300;*/
int a = 10;
int b = 30;
const int* const p = &a;
//p = 100;
//*p = 100;
system("pause");
return EXIT_SUCCESS;
}
指针类型的作用
指针的加减运算
数据类型对指针的作用
间接引用
决定了从指针存储地址开始,向后读取的字节数,与指针本身存储空间无关
加减运算
决定了指针进行 +1/-1操作后加过的字节数
指针 * / % : error!!!
指针 +-整数
- 普通指针变量 +-整数
char*p 打印p,p+1 偏过1字节
short*p 打印p,p+1 偏过2字节
int *p 打印·p,p+1 偏过4字节
- 在数组中 +- 整数
short arr[] = {1,3,5,8}
int *p = arr;
p+3; // 向右(后)偏过 3 个元素
p-2; // 向前(左)偏过 2 个元素
- 数组名+1
- 加过一个数组大小(数组元素个数x sizeof(数组元素类型))
- 指针+-指针:
- 指针+指针 :错误
- 指针-指针
- 普通变量来说,语法允许,无实际意义
- 数组来说:偏移过的元素个数
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
int main(void)
{
//指针在数组中加减整数
/*int a[] = {1,2,3,4,5,6,7,8,9,0};
int* p = &a[5];
printf("p-2 = %p\n",p-2);
printf("&a[3]=%p\n",&a[3]);*/
//数组名+1
/*short a[10] = {1,2,3,4,5,6,7,8,9,0};
printf("a=%p\n",a);
printf("&a[0] = %p\n",a+1);
printf("&a=%p\n",&a);
printf("&a+1=%p\n",&a+1);*/
// 指针加减指针
int a[10] = { 1,2,3,4,5,6,7,8,9,0 };
int *p = a;
for (size_t i = 0; i < 10; i++)
{
printf("%d\n",*p);
p++;
}
printf("p-a=%d\n",p-a);
system("pause");
return EXIT_SUCCESS;
}
指针操作数组
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
int main0701(void)
{
//int a[] = { 1,2,3,4,5,6,7,8,9,0 };
//int n = sizeof(a) / sizeof(a[0]);
//int *p = a;
//printf("sizeof(a)= %u\n",sizeof(a)); // 数组大小
//printf("sizeof(p)= %u\n",sizeof(p)); //指针大小
//
//for (size_t i = 0; i < n; i++)
//{
// printf("%d ",a[i]);
// printf("%d ",*(a+i));
// printf("%d ", p[i]);
// printf("%d ", *(p+i));
//}
system("pause");
return EXIT_SUCCESS;
}
int main0702(void)
{
int arr[] = { 1, 2, 4, 5, 6, 7, 8, 9, 0 };
int* p = arr;
int n = sizeof(arr) / sizeof(arr[0]);
printf("first p = %p\n", p);
for (size_t i = 0; i < n; i++)
{
printf("%d ", *p);
p++; // p = p+1; 一次加过一个int大小。 一个元素。
}
putchar('\n');
printf("last p = %p\n", p);
system("pause");
return EXIT_SUCCESS;
}
int main0703(void)
{
int arr[10];
int n = sizeof(arr) / sizeof(arr[0]);
int* p = arr;
for (size_t i = 0; i < n; i++)
{
*(p + i) = 10 + i;
}
for (size_t i = 0; i < n; i++)
{
printf("%d",*p);
p++;
}
printf("\n");
system("pause");
return EXIT_SUCCESS;
}
指针实现strlen函数
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
int mystrlen(char arr[]);
int main0701(void)
{
char abc[] = "hello world";
int ret = mystrlen2(abc); // 实际参数 abc
printf("ret = %d\n", ret);
system("pause");
return EXIT_SUCCESS;
}
// 借助数组 实现
int mystrlen(char str[])
{
int i = 0;
while (str[i] != '\0')
{
i++;
}
return i;
}
// 借助指针++ 实现
int mystrlen2(char str[])
{
char *p = str;
while (*p != '\0')
{
p++;
}
return p-str; // 返回数组元素的个数。
}
指针的比较运算
普通变量,语法允许,五十几意义
数组来说,地址之间可以进行比较大小,可以得到元素存储先后顺序
3) int *p;
p = NULL; // 这两行等价于: int *p = NULL;
if (p != NULL)
printf(" p is not NULL");
else
printf(" p is NULL");
指针数组:
一个存储地址数组,数组内部所有元素地址
1)
int a = 10;
int b = 20;
int c = 30;
int *arr[] = {&a, &b, &c}; // 数组元素为 整型变量 地址
2)
int a[] = { 10 };
int b[] = { 20 };
int c[] = { 30 };
int *arr[] = { a, b, c }; // 数组元素为 数组 地址。
指针数组本质是一个二级指针
二维数组,也是一个二级指针
多级指针
多级指针:
int a = 0;
int *p = &a; 一级指针是 变量的地址。
int **pp = &p; 二级指针是 一级指针的地址。
int ***ppp = &pp; 三级指针是 二级指针的地址。
int ****pppp = &ppp; 四级指针是 三级指针的地址。 【了解】
......
多级指针,不能 跳跃定义!
对应关系:
ppp == &pp; 三级指针
*ppp == pp == &p; 二级指针
**ppp == *pp == p == &a 一级指针
***ppp == **pp == *p == a 普通整型变量
day07
栈帧
当调用函数时,系统会在stack空间上申请一块内存区域,用来供函数调用,主要存放形参和局部变量(定义在函数内部)
当函数调用结束,这块内存区域自动被释放(消失)
传值操作
传值:函数调用期间,实参将自己的值拷贝一份,给形参
传址:函数调用期间,实参将地址值,拷贝一份给形参
地址值,在swap函数栈帧内部,修改了main函数栈帧内部局部变量值
传址操作
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
int swap(int a, int b);
int swap2(int* a, int* b);
int main12(void)
{
int m = 23;
int n = 57;
printf("before m = %d,n = %d\n",m,n);
//swap(m,n);
swap2(&m,&n);
printf("after m= %d,n=%d\n",m,n);
system("pause");
return EXIT_SUCCESS;
}
int swap(int a , int b)
{
int tmp = 0;
tmp = a;
a = b;
b = tmp;
return 0;
}
int swap2(int* a, int* b)
{
int tmp = 0;
tmp = *a;
*a = *b;
*b = tmp;
return 0;
}
指针做函数参数
int swap2(int *a, int *b);
int swap2(char *a, char *b);
调用时,传有效的地址值
数组做函数参数
void BubbleSort(int arr[10]) == void BubbleSort(int arr[]) == void BubbleSort(int *arr)
传递不再是数组而是数组的首地址(一个指针)
所以当整型数组做函数参数,通常在函数定义,封装2个参数,一个表数组首地址一个表元素个数
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
//void BubbleSort(int arr[]) // void BubbleSort(int *arr)
void BubbleSort(int* arr, int n) // 传一个首地址,传一个元素个数
{
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - 1 - i; j++)
{
if (arr[j] > arr[j + 1])
{
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
int main13(void)
{
int arr[] = { 5, 89, 3, 22, 40, 31, 9, 22, 67, 28, 45, 78 };
printf("main: sizeof(arr) = %d\n", sizeof(arr));
int n = sizeof(arr) / sizeof(arr[0]); // 传个数到
BubbleSort(arr, n); // 传递两个参数
for (size_t i = 0; i < n; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
system("pause");
return EXIT_SUCCESS;
}
指针做函数返回值
int *test_func(int a, int b);
指针做函数返回值,不能返回[局部变量地址值]
数组做函数返回值,C语言不允许,只能写成指针形式
指针和字符串
char str1[] = {'h','i','\0'}; 变量,可读可写
char str2[] = 'hi'; 变量,可读可写
char *str3 = 'hi'; 常量,只读
str3变量,存储的是字符串常量 'hi'中的首个字符 'hi' 的地址值
str3[1] = 'H' 错误
char *str4 = {'h', 'i', '\0'}; // 错误!!!
当字符串(字符数组)做函数参数,不需要提供2个参数,因为每个字符串都有'\0'
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
int main15(void)
{
char str1[] = "hello"; // {'h',, 'e', 'l', 'l', 'o', '\0'}
char m[] = "hello";
char* str2 = "hello"; // "hello" 是一个字符串常量, 不能修改。
char* n = "hello";
str1[0] = 'R';
str2[0] = 'R';
printf("str1 = %p\n", str1);
printf("m = %p\n", m);
printf("str2 = %p\n", str2);
printf("n = %p\n", n);
system("pause");
return EXIT_SUCCESS;
}
字符串比较
练习:比较两个字符串: strcmp();实现
比较 str1 和 str2, 如果相同返回0, 不同则依次比较ASCII码,str1 > str2 返回1,否则返回-1
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
int mystrcmp(char* str1, char* str2)
{
int i = 0;
while (str1[i]==str2[i])
{
if (str1[i]=='\0')
{
return 0;
}
i++;
}
return str1[i] > str2[i] ? 1 : -1;
}
int mystrcmp2(char* str1, char *str2)
{
while (*str1==*str2)
{
if (*str1=='\0')
{
return 0;
}
str1++;
str2++;
}
return *str1 > *str2 ? 1 : -1;
}
int main(void)
{
char* str1 = "helloz";
char* str2 = "hellob";
int ret = mystrcmp(str1,str2);
int ret2 = mystrcmp2(str1,str2);
if (ret ==0)
{
printf("相同\n");
}
else if (ret==1)
{
printf("str1>str2\n");
}
else if (ret ==-1)
{
printf("str1<str2\n");
}
else
{
printf("异常\n");
}
system("pause");
return EXIT_SUCCESS;
}
练习:字符串拷贝:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
//数组
void mystrcpy(char* src, char* dst)
{
int i = 0;
while (src[i]!=0)
{
dst[i] = src[i];
i++;
}
dst[i] = '\0';
}
// 指针版
void mystrcpy2(char* src, char* dst)
{
while (*src !='\0')
{
*dst = *src;
src++;
dst++;
}
*dst = '\0';
}
int main17(void)
{
char* src = "helloworld";
char dst[100] = { 0 };
//mystrcpy(src, dst);
mystrcpy2(src, dst);
printf("dst = %s\n",dst);
system("pause");
return EXIT_SUCCESS;
}
字符串去空格
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
void str_no_space(char* src, char* dst)
{
int i = 0;
int j = 0;
while (src[i] != 0)
{
if (src[i] != ' ')
{
dst[j] = src[i];
j++;
}
i++;
}
dst[j] = '\0';
}
// 指针版
void str_no_space2(char* src, char* dst)
{
int i = 0;
int j = 0;
while (*src != 0)
{
if (*src != ' ')
{
*dst = *src;
dst++;
}
src++;
}
*dst = '\0';
}
int main(void)
{
char str[] = "wo ai ni";
char dst[100] = { 0 };
//str_no_space(str, dst);
str_no_space2(str, dst);
printf("dst = %s\n",dst);
system("pause");
return EXIT_SUCCESS;
}
字符串找字符
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
char* mystrch(char* str, char* ch)
{
while (*str)
{
if (*str==ch)
{
return str;
}
str++;
}
return NULL;
}
char* mystrch2(char* str, char ch)
{
int i = 0;
while (str[i])
{
if (str[i]==ch)
{
return &str[i];
}
i++;
}
return NULL;
}
int main19(void)
{
char str[] = "hello world";
char ch = 'o';
char* ret = NULL;
//ret = mystrch(str,ch);
ret = mystrch2(str,ch);
printf("ret = %s\n",ret);
system("pause");
return EXIT_SUCCESS;
}
带参数的main
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
int main20(int argc,char *argv[])
{
int i;
for (size_t i = 0; i < argc; i++)
{
printf("argv[%d] = %s\n",i,argv[i]);
}
system("pause");
return EXIT_SUCCESS;
}
字符串统计子串出现的次数
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
int main2101(void)
{
char* ret = strstr("hellollollollo","llo");
printf("ret = %s\n",ret);
system("pause");
return EXIT_SUCCESS;
}
int str_times(char* str, char* substr)
{
int count = 0;
char * p = strstr(str, substr);
while (p!=NULL)
{
count++;
p += strlen(substr);
p = strstr(p, substr);
}
return count;
}
int main(void)
{
char str[] = "helloabclloxyzllo";
char substr[] = "llo";
int ret = str_times(str,substr);
printf("出现%d次\n",ret);
}
day08
非空字符串元素个数
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
int no_space_str(char *str)
{
int count = 0;
char *p = str;
while (*p)
{
if (*p != ' ')
{
count++;
}
p++;
}
return count;
}
int main0101(void)
{
char str[] = "ni chou sha";
int ret = no_space_str(str);
printf("%d\n", ret);
system("pause");
return EXIT_SUCCESS;
}
字符串逆序
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
// o e l l h
// 字符串逆序
void str_inserse(char *str)
{
//int i, j; // str[i] *(str+i)
char *start = str; // 记录首元素地址
char *end = str + strlen(str) - 1; // 记录最后一个元素地址。
while (start < end) // 首元素地址是否 < 最后一个元素地址
{
char tmp = *start; // 三杯水 char 元素交换
*start = *end;
*end = tmp;
start++; // 首元素对应指针后移
end--; // 尾元素对应指针前移
}
}
// 判断回文字符串 abcddpba
int str_abcbb(char *str)
{
char *start = str; // 记录首元素地址
char *end = str + strlen(str) - 1;// 记录最后一个元素地址。
while (start < end) // 首元素地址是否 < 最后一个元素地址
{
if (*start != *end) // 判断字符是否一致。
{
return 0; // 0 表示非 回文
}
start++;
end--;
}
return 1; // 1 表示 回文
}
int main0201(void)
{
char str[] = "this is a test";
str_inserse(str);
printf("str=%s\n ---------------------\n", str);
char s2[] = "abcmncba";
int ret = str_abcbb(s2);
if (ret == 0)
printf("不是回文\n");
else if (ret == 1)
printf("是回文\n");
system("pause");
return EXIT_SUCCESS;
}
字符串拷贝
strcpy 将src的内容,拷贝给dest 返回dest,保证dest空间足够大,不安全
char *strcpy(char *dest,const char *src)
函数调用结束,返回值和dest结果一致
strncpy
将src的内容,拷贝给dest,只拷贝n个字节,通常n与dest对应空间一致1
默认不添加 ‘\0’
char *strncpy(char *dest,const char *src,size_t n)
特性: n>src,只拷贝src大小
n<src 只拷贝n个字节大小,不添加 ‘0’
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
int main2401(void)
{
char src[] = "abc efg zhangsan ";
char dest[10] = { 0 };
char* p = strcpy(dest,src); // 字符串src 拷贝给 dest
printf("p = %s\n",p);
printf("dest=%s\n",dest);
system("pause");
return EXIT_SUCCESS;
}
int main2402()
{
char src[] = "hello world";
char dest[100] = {0};
char* p = strncpy(dest, src, 100);
for (size_t i = 0; i < 10; i++)
{
printf("%c\n",p[i]);
}
printf("p = %s\n",p);
printf("dest = %s\n",dest);
}
字符串拼接
strcat
将src的内容,拼接到dest后,返回拼接后的字符串,要保证dest空间足够大
char *strcat(char *dest,const char *src)
strncat
有src前n个字符,拼接到dest后,形成一个新的字符串,保证dest空间足够大
char *strncat(char *dest, const char *src, size_t n);
函数调用结束返回值和dest参数结果一致
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
int main2501(void)
{
char src[] = "world";
char dest[] = "hello";
char* p = strcat(dest, src);
printf("p = %s\n",p);
printf("dest = %s\n",dest);
system("pause");
return EXIT_SUCCESS;
}
int main2502()
{
char src[] = "world";
char dest[] = "hello";
char* p = strncat(dest, src, 3); // 取三个字符从src中并拼接
printf("p = %s\n", p);
printf("dest = %s\n", dest);
}
字符串比较
不能使用 ><>=<=!=
strcmp: 比较s1和s2两个字符串,如果相等,返回0如果不相等,进一步比s1和s2对应的ASCII码
s1>s2返回1
s1<s2返回-1
int strcmp(const char *s1, const char *s2);
strncmp:
int strncmp(const char *s1, const char *s2, size_t n);
比较s1和s2两个字符串的前n个字符,
如果相等 返回0。如果不相等,进一步表 s1 和 s2 对应位 ASCII码值。(不比字符串ASCII码的和)
s1 > s2 返回1
s1 < s2 返回-1
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
int main2601(void)
{
char* str1 = "helloworld";
char* str2 = "helloz";
printf("ret = %d\n",strcmp(str1,str2));
system("pause");
return EXIT_SUCCESS;
}
int main2602()
{
char* str1 = "helloworld";
char* str2 = "helloz";
printf("ret = %d\n",strncmp(str1,str2,8));//取前四个字符比较
}
字符格式化输出输入
sprintf() s–string
int sprintf(char *str, const char *format, ...);
对应 printf 将原来的格式化字符串写到参数1str中
printf("%d+%d=%d\n", 10, 24, 10+24);
char str[100];
sprintf(str, "%d+%d=%d\n", 10, 24, 10+24); 格式串写入str数组中。
sscanf()
int sscanf(const char *str, const char *format, ...);
对应scanf 将原来从屏幕获取的格式化字符串,从参数1str中获取
scanf("%d+%d=%d", &a, &b, &c);
char str[]= "10+24=45";
sscanf(str, "%d+%d=%d", &a, &b, &c); a --> 10, b --> 24, c --> 45
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
int main2701(void)
{
char buf[100] = { 0 };
sprintf(buf,"%d+%d=%d",10,20,30);
puts(buf);
system("pause");
return EXIT_SUCCESS;
}
int main2702()
{
char buf[100] = { 0 };
int a, b, c;
/*char str[] = {0};
scanf("%d %d %d",str);*/
char str[] = "13+56=89";
sscanf(str,"%d+%d=%d",&a,&b,&c);
printf("a = %d\n",a);
printf("b = %d\n",b);
printf("c = %d\n",c);
}
字符串分割
strtok() 按照既定得到分隔符来拆分字符串“www.baidu.com” --> "www\0baidu.com"
char *strtok(char *str, const char *delim);
参数1:待拆分的字符串
参数:分割符组成的分割串
返回:字符串拆分后首地址,拆分将分隔符用“\0”替换
特性
strtok 拆分字符串是直接在原串上操作,所以要求参数1必须可读可写(char *str = "www.baidu.com" 不行!!!)
第一次拆分,参数1传待拆分原串,第1+次拆分,参数1传NULL,
atoi/atof/atol:
使用这类函数进行转换,要求,原串必须是可转换的字符串。
错误使用:"abc123" --> 0; "12abc345" ---> 12; "123xyz" -->123
atoi:字符串 转 整数。
int atoi(const char *nptr);
atof:字符串 转 浮点数
atol:字符串 转 长整数
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
int main2801(void)
{
char str[] = "www.baidu.com";
char* p = strtok(str,"."); // 第一次拆分,参数1传,待拆分的原串
while (p!=NULL)
{
p = strtok(NULL,"."); //第1+次拆分是,参数传1NULL
printf("%s\n",p);
}
system("pause");
return EXIT_SUCCESS;
}
int main2802()
{
char str[] = "www.abcdef.hijk$abcda";
char* p = strtok(str,"$.");
while (p!=NULL)
{
p = strtok(NULL,".$");
printf("p=%s\n",p);
}
}
字符串转为浮点,整型
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
static int a = 1234567;
void test1()
{
static int b = 0;
printf("b = %d\n",b++);
}
int main29(void)
{
char str[] = "abc345";
int num = atoi(str);
printf("num = %d\n",num);
char str1[] = " 10";
int num1 = atoi(str1);
printf("num1 = %d\n", num1);
char str2[] = "0.123f";
double num2 = atof(str2);
printf("num2 = %.2lf\n",num2);
char str3[] = "123L";
long num3 = atol(str3);
printf("num3 = %ld\n",num3);
system("pause");
return EXIT_SUCCESS;
}
局部变量:
概念:定义在函数内部变量
作用域:从定义位置开始,到包裹该变量的第一个右大括号结束
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
void test2(); //全局函数声明
int m = 3434;
int main(void)
{
int i = 1000101;
for (size_t j = 0; j < 10; j++)
{
printf("j=%d\n",j);
}
printf("i2 = %d\n",i);
system("pause");
return EXIT_SUCCESS;
}
全局变量
概念:定义在函数外部变量
作用域,从定义位置开始,默认到本文件内部,其他文件如果想使用,可以通过声明的方式将作用域到出
static全局变量
定义语法:全局变量定义之前添加static关键字 static int a = 10;
作用域:被限制在本文件内部,不允许通过声明导出到其他文件
static 局部变量
定义语法:在局部变量定义之前添加static 关键字
特性:静态局部变量只定义一次,在全局位置,通常用来做计数器
作用域:从定义位置开始,到把偶偶该变量的右大括号结束
全局函数:函数
定义:函数原型+函数体
static函数,
定义语法 :static +函数原型+函数体
static 函数只能在本文件内部使用,其他文件即使声明也无效
生命周期
局部变量:从变量定义开始,函数调用完成,函数内部
全局变量,程序启动开始,程序终止结束--程序执行期间
static 局部变量,程序启动开始,程序终止结束--程序执行期间
static 全局变量,程序启动开始,程序终止结束--程序执行期间
全局函数,程序启动开始,程序终止结束--程序执行期间
static 函数,程序启动开始,程序终止结束--程序执行期间
内存4区模型
内存4区
代码段:.text段,程序源代码
数据段,只读数据段 .rodata 初始化数据段 .data 段,未初始化数据段.bss段
stack :栈 在其之上开辟栈帧,windows 1M--10M,LINUX 8M –16M
heap 堆 给用户自定义数据提供空间 约等于1.3G+
开辟释放heap空间
void *malloc(size_t size); 申请size 大小空间
返回实际申请到内存空间首地址【通常拿来当数组用】
void free(void *ptr); 释放申请空间
参数,malloc 返回地址值
使用heap 空间
空间时连续,当成数组使用
free后空间,不会立即失效,通常free后地址置为NULL
free地址必须是 malloc 申请地址,否则出错
如果malloc之后地址一定会变化,那么使用临时变量tmp保存
二级指针
二级指针对应的heap空间
申请外层指针 char **p = (char **)malloc(sizeof(char *) * 5);
申请内层指针
for(i = 0; i < 5; i++)
{
p[i] = (char *)malloc(sizeof(char) *10);
}
使用:不能修改p的值
for(i = 0; i < 5; i++)
{
strcpy(p[i], "helloheap");
}
释放内层
for(i = 0; i < 5; i++)
{
free(p[i]);
}
释放外层
free(p);
day09
结构体
数组:描述一组具有相同类型数据的有序集合,用于处理类型相同的数据的运算
结构体变量定义和初始化
- 先声明结构体类型在定义变量名
- 在声明类型同时定义变量
- 直接定义结构体类型变量(无类型名)
结构体类型:指定一个结构体类型,相当于一个模型,但其中并无具体数据,系统对它也不分配实际内存单元
结构体变量:系统根据结构体类型分配空间
struct 结构体名称
{
结构体成员列表
}
定义结构体变量
struct 结构体名称 结构体变量名
结构体变量名,结构体成员列表 = 值
如果是字符串,需要用strcpy
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
struct students
{
// 定义结构体格式
// 成员列表
char name[21];
unsigned int age;
char tel[16];
float scores[3];
char sex;
}stu = { "赵三",50,"15044701465",100.0f,200,300,'M' };
int main(void)
{
//struct students stu = { .name="王硕", .age = 13, .tel = "1234567",.scores[0] =100,.scores[1] = 200,.scores[2] = 300,.sex='M'};
//struct students stu = { .sex = 'M', .name = "王五", .tel = "123456789" };
//struct students stu = {"赵三",50,"15044701465",100.0f,200,300,'M'};
/*struct students stu;
stu.age = 50;
strcpy(stu.name,"吴祖龙");
strcpy(stu.tel,"1234567");
stu.scores[0] = 12;
stu.scores[1] = 12;
stu.scores[2] = 12;
stu.sex = 'M';*/
/*struct students stu;*/
/*stu.age = 50;
strcpy(stu.name,"吴祖龙");
strcpy(stu.tel,"1234567");
stu.scores[0] = 12;
stu.scores[1] = 12;
stu.scores[2] = 12;
stu.sex = 'M';*/
printf("姓名 %s\n",stu.name);
printf("年龄 %d\n",stu.age);
printf("电话 %s\n",stu.tel);
printf("成绩 %.1f %.1f %.1f\n",stu.scores[0],stu.scores[1],stu.scores[2]);
printf("性别 %s\n",stu.sex == 'M'?"男":"女");
system("pause");
return EXIT_SUCCESS;
}
结构体大小
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
// 结构体需要根据数据结构进行数据类型对齐
struct stus
{
char name[20];
unsigned int age;
char tel[15];
float scores[3];
char sex;
}stu;
struct stus
{
char* p;
char arr[2];
int c;
short d;
double f;
long g;
float h[2];
};
int main(void)
{
printf("结构体大小%d\n",sizeof(stu));
system("pause");
return EXIT_SUCCESS;
}
结构体数组
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
struct stu
{
// 定义结构体格式
// 成员列表
char name[21];
unsigned int age;
char tel[16];
float scores[3];
char sex;
};
int main(void)
{
// 结构体数组
struct stu s[2];
for (size_t i = 0; i < 2; i++)
{
printf("输入姓名,年龄,电话,成绩,性别\n");
scanf("%s%d%s%f%f%f,%c",s[i].name,&s[i].age,s[i].tel,&s[i].scores[0],&s[i].scores[1],&s[i].scores[2],&s[i].sex);
}
for (size_t i = 0; i < 2; i++)
{
printf("姓名 %s\n", s[i].name);
printf("年龄 %d\n", s[i].age);
printf("电话 %s\n", s[i].tel);
printf("成绩 %.1f %.1f %.1f\n", s[i].scores[0], s[i].scores[1], s[i].scores[2]);
printf("性别 %s\n", s[i].sex == 'M' ? "男" : "女");
}
system("pause");
return EXIT_SUCCESS;
}
案例学生成绩
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
struct stu2
{
char name[2];
float scores[3];
};
int main4(void)
{
struct stu2 s[3];
for (int i = 0; i < 3; i++)
{
printf("输入姓名 成绩 \n");
scanf("%s%f%f%f",s[i].name,&s[i].scores[0], &s[i].scores[1], &s[i].scores[2]);
}
// 冒泡排序
for (size_t i = 0; i < 3-1; i++)
{
for (size_t j = 0; j < 3-1-i; j++)
{
int sum1 = s[j].scores[0] + s[j].scores[1] + s[j].scores[2];
int sum2 = s[j+1].scores[0] + s[j+1].scores[1] + s[j+1].scores[2];
if (sum1>sum2)
{
// 三杯水交换
// 交换姓名
char* tmp[21] = { 0 };
strcpy(tmp,s[j].name);
strcpy(s[j].name,s[j+1].name);
strcpy(s[j+1].name,tmp);
//交换成绩
for (size_t k = 0; k < 3; k++)
{
float tmp = s[j].scores[k];
s[j].scores[k] = s[j + 1].scores[k];
s[j + 1].scores[k] = tmp;
}
}
}
}
for (int i = 0; i < 3; i++)
{
printf("姓名%s\n",s[i].name);
printf("成绩 %.lf %.lf %.lf\n", s[i].scores[0], s[i].scores[1], s[i].scores[2]);
}
system("pause");
return EXIT_SUCCESS;
}
结构体函数
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
struct info
{
char name[21];
int age;
};
void fun01(struct info s)
{
strcpy(s.name, "李四");
s.age = 20;
}
int main05(void)
{
struct info s = {"张三",18};
fun01(s);
printf("%s %d\n",s.name,s.age);
system("pause");
return EXIT_SUCCESS;
}
案例结构体函数
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
struct stu2
{
char name[2];
float scores[3];
};
int main12(void)
{
struct stu2 s[3];
for (int i = 0; i < 3; i++)
{
printf("输入姓名 成绩 \n");
scanf("%s%f%f%f", s[i].name, &s[i].scores[0], &s[i].scores[1], &s[i].scores[2]);
}
// 冒泡排序
for (size_t i = 0; i < 3 - 1; i++)
{
for (size_t j = 0; j < 3 - 1 - i; j++)
{
int sum1 = s[j].scores[0] + s[j].scores[1] + s[j].scores[2];
int sum2 = s[j + 1].scores[0] + s[j + 1].scores[1] + s[j + 1].scores[2];
if (sum1 > sum2)
{
// 三杯水交换
// 交换姓名
char* tmp[21] = { 0 };
strcpy(tmp, s[j].name);
strcpy(s[j].name, s[j + 1].name);
strcpy(s[j + 1].name, tmp);
//交换成绩
for (size_t k = 0; k < 3; k++)
{
float tmp = s[j].scores[k];
s[j].scores[k] = s[j + 1].scores[k];
s[j + 1].scores[k] = tmp;
}
}
}
}
for (int i = 0; i < 3; i++)
{
printf("姓名%s\n", s[i].name);
printf("成绩 %.lf %.lf %.lf\n", s[i].scores[0], s[i].scores[1], s[i].scores[2]);
}
system("pause");
return EXIT_SUCCESS;
}
结构体嵌套
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
struct stra
{
int a;
float b;
char c;
}abc;
struct strb
{
double d;
char* e;
short f;
struct stra abc;
};
int main6(void)
{
struct strb strbb;
strbb.d = 10.0f;
strbb.abc.a = 100;
//printf("%d\n",strbb.abc.a);
printf("%d\n",sizeof(strbb));
system("pause");
return EXIT_SUCCESS;
}
共用体
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
// 共用体,union 共用体名称,成员列表,共用体变量名
union vars
{
double a;
float b;
int c;
char d;
short e;
char arr[13];
}var;
int main7(void)
{
var.a = 100;
var.b = 3.14;
var.c = 66;
printf("%.f\n",var.a);
printf("%.f\n",var.b);
printf("%.f\n",var.c);
printf("%d\n",sizeof(var));
system("pause");
return EXIT_SUCCESS;
}
结构体和指针
在堆中开辟结构体指针
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
struct stuinfo
{
char* name;
int age;
};
int main08(void)
{
struct stuinfo si;
si.name = (char*)malloc(sizeof(char) * 21);
strcpy(si.name, "张三");
si.age = 18;
printf("%s %d\n",si.name,si.age);
system("pause");
return EXIT_SUCCESS;
}
堆空间开辟结构
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
struct tec
{
char* name;
int age;
}t;
int main10(void)
{
malloc(sizeof(t)*5);
struct tec*p = (struct tec*)malloc(sizeof(t));
p->name = (char*)malloc(sizeof(char)*22);
strcpy(p->name, "牛儿");
p->age = 18;
printf("%s,%d\n",p->name,p->age);
if (p->name!=NULL)
{
free(p->name);
p->name = NULL;
}
if (p)
{
free(p);
p = NULL;
}
system("pause");
return EXIT_SUCCESS;
}
枚举
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
enum colors
{
red=10,blue,yellow=20,black,whilt,green
}clo;
int main13(void)
{
clo = 0;
int val;
scanf("%d",&val);
switch (clo)
{
case red:
printf("请输入密码");
clo = 1;
printf("红色\n");
break;
case blue:
break;
case yellow:
break;
case black:
break;
case whilt:
break;
case green:
break;
default:
break;
}
system("pause");
return EXIT_SUCCESS;
}
typedef
typedef为C语言的关键字,作用是为一种数据类型(基本类型或自定义数据类型)定义一个新名字,不能创建新类型。
l 与#define不同,typedef仅限于数据类型,而不是能是表达式或具体的值
l #define发生在预处理,typedef发生在编译阶段
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
typedef unsigned long long ull;
struct student1
{
char name[20];
char sex;
};
typedef struct student1 sinfo;
int main(void)
{
sinfo s1;
struct student1 sil;
ull a = 10;
auto unsigned int a = 20;
printf("%d\n",a);
system("pause");
return EXIT_SUCCESS;
}
day10
共用体和联合体
union test {
char ch;
short sh;
int var;
};
联合体,内部素有成员变量一直,等同于整个联合体地址
联合体大小,是内部成员变量中,最大的那个成员变量大小(对齐)
修改其中任意一个变量的值,其他成员变量会随之修改
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
typedef union test {
char ch;
short sh;
int a;
}test_t;
int main1501(void)
{
test_t obj;
obj.a = 0x87654321;
printf("&obj = %p\n", &obj);
printf("&obj.ch = %p\n", &obj.ch);
printf("&obj.sh = %p\n", &obj.sh);
printf("&obj.a = %p\n", &obj.a);
printf("sizeof(test_t) = %u\n", sizeof(test_t));
printf("a = 0x%x\n", obj.a);
printf("sh = 0x%x\n", obj.sh);
printf("ch = 0x%x\n", obj.ch);
obj.ch = 0xFF;
printf("a = 0x%x\n", obj.a);
printf("sh = 0x%x\n", obj.sh);
printf("ch = 0x%x\n", obj.ch);
system("pause");
return EXIT_SUCCESS;
}
enum clocor { red,green,blue,black,pinkl=18,yellow};
int main1502(void)
{
int flg = 2;
if (flg = blue)
{
printf("blue is 2\n");
}
else
{
printf("blue is not 2,blue = %d\n",blue);
}
printf("yellow = %d\n",yellow);
}
枚举
enum color(枚举常量)
enum color{red,gren,blue,black,pink,yellow};
枚举常量:整形常量,不能是浮点数,可以是负值,默认初值是0开始,后续常量较前一个常量+1
可以给任意一个常量赋任意初值,后续常量较前一个常量+1
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
/*
enum colors
{
red=10,blue,yellow=20,black,whilt,green
}clo;
int main13(void)
{
clo = 0;
int val;
scanf("%d",&val);
switch (clo)
{
case red:
printf("请输入密码");
clo = 1;
printf("红色\n");
break;
case blue:
break;
case yellow:
break;
case black:
break;
case whilt:
break;
case green:
break;
default:
break;
}
system("pause");
return EXIT_SUCCESS;
}
*/
读写文件 与printf ,scanf关联
printf ---屏幕--标准输出
scanf—键盘---标准输入
perror --屏幕---标准错误
系统文件:
标准输入---stdin—0
标准输出--stdout—1
标准错误---stderr–2
应用程序启动,自动被打开,程序执行结束时,自动被关闭---隐式回收
文件指针普通指针区别:
FILE*fp = NULL
借助文件操作函数来改变fp为空野指针的状况,fopen(); 相当于 fp–malloc()
操作文件,使用文件读写函数来完成,fputc,fgetc,fgets,fputs,fread,fwrite
文件分类
设备文件
屏幕,键盘,磁盘,网卡,声卡,显卡
磁盘文件:ASCII
二进制文件 0101二进制编码
文件操作
打开文件 fopen() FILE*fp
读写
关闭
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
int main16(void)
{
printf("helllo file\n");
system("pause");
return EXIT_SUCCESS;
}
打开、关闭文件函数:
FILE * fopen(const char * filename, const char * mode);
参1:待打开文件的文件名(访问路径)
参2:文件打开权限:
"r": 只读方式打开文件, 文件不存在,报错。存在,以只读方式打开。
"w": 只写方式打开文件, 文件不存在,创建一个空文件。文件如果存在,清空并打开。
"w+":读、写方式打开文件,文件不存在,创建一个空文件。文件如果存在,清空并打开。
"r+":读、写方式打开文件, 文件不存在,报错。存在,以读写方式打开。
"a": 以追加的方式打开文件。
"b": 操作的文件是一个二进制文件(Windows)
返回值:成功:返回打开文件的文件指针
失败:NULL
int fclose(FILE * stream);
参1:打开文件的fp(fopen的返回值)
返回值:成功 :0, 失败: -1;
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
int main17(void)
{
FILE* fp = NULL;
fp = fopen("test2.txt","w");
if (fp == NULL)
{
perror("fopen error");
getchar();
return -1;
}
fclose(fp);
printf("---------finish\n");
system("pause");
return EXIT_SUCCESS;
}
文件访问路径:
绝对路径:
从系统磁盘的 根盘符开始,找到待访问的文件路径
Windows书写方法:
1)C:\\Users\\afei\\Desktop\\06-文件分类.avi
2)C:/Users/afei/Desktop/06-文件分类.avi --- 也使用于Linux。
相对路径:
1)如果在VS环境下,编译执行(Ctrl+F5),文件相对路径是指相对于 day10.vcxproj 所在目录位置。
2)如果是双击 xxx.exe 文件执行,文件的相对路径是相对于 xxx.exe 所在目录位置。
按字符写入文件 fputc
int fputc(int ch,FILE*stream);
参数1:待写入的字符
参数2:打开文件fp(fopen的返回值)
返回值:成功:写入文件中的字符对应的ASCII码,失败返回-1
文本文件的结束标记: EOF ---》 -1
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
int main18(void)
{
char* filename = "test-4.txt";
FILE* fp = fopen(filename,"w");
if (fp == NULL)
{
perror("fopen error");
return -1;
}
int ret = fputc("B",fp);
printf("ret = %d\n",ret);
fclose(fp);
printf("0-------------------0");
system("pause");
return EXIT_SUCCESS;
}
/*int main1802()
{
char* filename = "test-4.txt";
int ret = 0;
FILE* fp = fopen(filename, "w");
if (fp == NULL)
{
perror("fopen error");
return -1;
}
char ch = 'a';
while (ch<='z')
{
ret = fputc(ch, fp);
if (ret == -1)
{
perror("fputc error");
return -1;
}
ch++;
}*/
int main1803(void)
{
char* buf = "abcdefghijklmnopqrstuvwxyz";
char* filename = "test04.txt";
int ret = 0;
FILE* fp = fopen(filename, "w");
if (fp == NULL)
{
perror("fopen error");
return -1;
}
int n = strlen(buf);
for (size_t i = 0; i < n; i++)
{
ret = fputc(buf[i], fp);
if (ret == -1)
{
perror("fputc eror");
return -1;
}
}
fclose(fp);
system("pause");
return EXIT_SUCCESS;
}
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
void write_file()
{
FILE* fp = fopen("05test.txt", "w");
if (fp == NULL)
{
perror("fopen error");
return -1;
}
fputc('a', fp);
fputc('b', fp);
fputc('c', fp);
fputc('d', fp);
fclose(fp);
}
void read_file()
{
char ch = 0;
FILE* fp = fopen("05test.txt","r");
if (fp == NULL)
{
perror("fopen error");
return -1;
}
while (1)
{
ch = fgetc(fp);
if (ch == EOF)
{
break;
}
printf("%d\n",ch);
}
fclose(fp);
}
int main19(void)
{
//write_file();
read_file();
system("pause");
return EXIT_SUCCESS;
}
feof()函数
- int feof(FILE * stream);
- 参数1 fopen 返回值
- 返回值:
- 到达文件结尾 非0 真
- 没有到达文件结尾0假
- 作用:
- 用来判断到达文件结尾,既可以判断文本文件,也可以判断二进制文件
- 特性:
- 要想使用feof 监测文件结束标记,就必须在该函数调用前,使用读文件函数
- feof()调用之前,必须有读文件函数调用
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
void read_file06()
{
char ch = 0;
FILE* fp = fopen("06test.txt","r");
if (fp ==NULL)
{
perror("fopen error");
return -1;
}
while (1)
{
ch = fgetc(fp);
if (feof(fp)) // 表示读到文件结尾
{
break; // 读到结尾停下来
}
printf("%d\n",ch);
}
fclose(fp);
}
void test_feof()
{
FILE* fp = fopen("06test.txt","r");
if (fp == NULL)
{
perror("fopen error");
return;
}
while (1)
{
printf("没有到达文件结尾\n");
fgetc(fp);
if (feof(fp))
{
break;
}
}
fclose(fp);
}
void write_file06()
{
FILE* fp = fopen("06test.txt", "w");
if (fp == NULL)
{
perror("fopen error");
return -1;
}
fputc('a',fp);
fputc('b',fp);
fputc(-1,fp);
fputc('c', fp);
fputc('d', fp);
fputc('\n', fp);
fclose(fp);
}
int main21(void)
{
//write_file06();
//read_file06();
//test_feof();
system("pause");
return EXIT_SUCCESS;
}
fgets()函数
-
获取一个字符串,以\n结束标记,自动添加\0,空间足够大,读\n空间不足舍弃\n,必须有\0
-
char * fgets(char * str, int size, FILE * stream); char buf[10]; hello --> hello\n\0
-
返回值:成功,读到字符串
失败;NULL
fputs()函数
- 写出一个字符串,如果字符串中没有\n,不会写\n
- int fputs(const char * str, FILE * stream);
- 返回值成功 0失败-1
练习: 获取用户键盘输入,写入文件。
假定:用户写入“:wq”终止接收用户输入,将之前的数据保存成一个文件。
FILE *fp = fopen("test07.txt", "w");
if (fp == NULL)
{
perror("fopen error");
return -1;
}
char buf[4096] = {0};
while (1)
{
fgets(buf, 4096, stdin);
if (strcmp(buf, ":wq\n") == 0) // 实际 fgets 读到的是“:wq\n”
{
break;
}
fputs(buf, fp);
}
fclose(fp);
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
int main20(void)
{
FILE* fp = fopen("test07.txt", "w");
if (fp == NULL)
{
perror("fopen error");
return -1;
}
char buf[4096] = { 0 };
while (1)
{
fgets(buf, 4096, stdin);
if (strcmp(buf, ":wq\n") == 0)
{
break;
}
fputs(buf, fp);
}
fclose(fp);
system("pause");
return EXIT_SUCCESS;
}
练习文件版四则运算
-
封装write_file 函数,将4则运算表达式写入
-
FILE * fp = fopen("w"); fputs("10/4=\n", fp); fputs("10+4=\n", fp); .... fputs("10*4=\n", fp);
-
封装read_file 函数将四则运算表达式独处,拆分运算写回
-
读出 FILE*fp = open("r"); while(1) { fgets(buf, sizeof(buf), fp); // buf中存储的 4则运算表达式 } 拆分 sscanf(buf, "%d%c%c=\n", &a, &ch, &b); // 得到运算数, 运算符 3.根据运算符,得出运算结果 switch(ch) { case '+': a+b; } 4.拼接结果到运算式上 char result[1024]; sprintf(reuslt, "%d%c%d=%d\n", a, ch, b, a+b); // reuslt 中包含带有结果的 运算式。 5.带有结果运算,拼接成一个字符串 char sum_ses[4096]; // 存总的字符串 -- "10/2=5\n10*3=30\n4+3=7\n8-6=2\n" strcat(sum_ses,reuslt); // 在while中循环拼接 6.重新打开文件,清空原有的四则运算表达式 fclose(fp); fp = fopen("w"); 7.拼接成一个字符串,写入到空文件中 fputs(sum_res);
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> #include<windows.h> void write_file08() { FILE* fp = fopen("08test.txt", "w"); if (fp == NULL) { perror("fopen error"); return -1; } fputs("10/2=\n",fp); fputs("10*3=\n",fp); fputs("4-2=\n",fp); fputs("10+2=\n",fp); fclose(fp); } int cal(char ch, int a, int b) { switch (ch) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; default: break; } } void read_file08() { char buf[4096] = { 0 }; char rest[4096] = { 0 }; char sum_res[4096] = { 0 }; int a, b, ret; char ch; FILE* fp = fopen("08test.txt", "r"); if (fp == NULL) { perror("fopen error"); return -1; } while (1) { fgets(buf,4096,fp); if (feof(fp)) { break; } sscanf(buf,"%d%c%d=\n",&a,&ch,&b); sprintf(rest,"%d%c%d=%d\n",a,ch,b,cal(ch,a,b)); strcat(sum_res,rest); } fclose(fp); // 将只有表达式没有结果文件关闭 fp = fopen("08test.txt","w"); if (fp == NULL) { perror("fopen error"); return -1; } fputs(sum_res, fp); // 将有有表达式和结果的字符串写进去 fclose(fp); } int main(void) { //write_file08(); //getchar(); read_file08(); system("pause"); return EXIT_SUCCESS; }
day11
printf --- sprintf --- fprintf:
变参函数:参数形参中 有“...”, 最后一个固参通常是格式描述串(包含格式匹配符), 函数的参数个数、类型、顺序由这个固参决定。
printf("hello");
printf("%s", "hello");
printf("ret = %d+%d\n", 10, 5);
printf("%d = %d%c%d\n", 10+5, 10, '+', 5); --> 屏幕
char buf[1024]; //缓冲区
sprintf(buf, "%d = %d%c%d\n", 10+5, 10, '+', 5); --> buf 中
FILE * fp = fopen();
fprintf(fp, "%d = %d%c%d\n", 10+5, 10, '+', 5); --> fp 对应的文件中
scanf --- sscanf --- fscanf
scanf("%d", &m); 键盘 --> m
char str[] = "98";
sscanf(str, "%d", &m); str --> m
FILE * fp = fopen("r");
fscanf(fp, "%d", &m); fp指向的文件中 --> m
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
void read_file06()
{
char ch = 0;
FILE* fp = fopen("06test.txt","r");
if (fp ==NULL)
{
perror("fopen error");
return -1;
}
while (1)
{
ch = fgetc(fp);
if (feof(fp)) // 表示读到文件结尾
{
break; // 读到结尾停下来
}
printf("%d\n",ch);
}
fclose(fp);
}
void test_feof()
{
FILE* fp = fopen("06test.txt","r");
if (fp == NULL)
{
perror("fopen error");
return;
}
while (1)
{
printf("没有到达文件结尾\n");
fgetc(fp);
if (feof(fp))
{
break;
}
}
fclose(fp);
}
void write_file06()
{
FILE* fp = fopen("06test.txt", "w");
if (fp == NULL)
{
perror("fopen error");
return -1;
}
fputc('a',fp);
fputc('b',fp);
fputc(-1,fp);
fputc('c', fp);
fputc('d', fp);
fputc('\n', fp);
fclose(fp);
}
int main21(void)
{
//write_file06();
//read_file06();
//test_feof();
system("pause");
return EXIT_SUCCESS;
}
fprint()函数
- 写
- int fprintf(FILE * stream, const char * format, ...);
- fscanf()函数
- 读 int fscanf(FILE * stream, const char * format, ...);
- 成功:正确匹配的个数
- 失败 -1
边界溢出:存储读取数据空间,在使用前清空
fscanf()函数
- 每次在调用时都会判断下一次是否匹配参数2,如果不匹配提前结束读文件
- feof(fp) 为真
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
void write_file01()
{
FILE* fp = fopen("abc.c", "w");
if (!fp) // fp == NULL
{
perror("fopen error");
return -1;
}
fprintf(fp,"%d\n",10);
fprintf(fp,"%d\n",8);
fprintf(fp,"%d\n",6);
fclose(fp);
}
void read_file01()
{
int a;
FILE* fp = fopen("abc.c", "r");
if (!fp) // fp == NULL
{
perror("fopen error");
return -1;
}
fscanf(fp,"%d\n",&a);
printf("%d\n",a);
a = 0;
fscanf(fp,"%d\n",&a);
fscanf(fp,"%d\n",&a);
printf("%d\n", a);
printf("%d\n", a);
fscanf(fp,"%d\n",&a);
fclose(fp);
}
void read_file02()
{
int a;
FILE* fp = fopen("abc.c", "r");
if (!fp) // fp == NULL
{
perror("fopen error");
return -1;
}
while (1)
{
fscanf(fp,"%d\n",&a);
printf("%d\n",a);
if (feof(fp))
{
break;
}
}
fclose(fp);
}
void read_file03()
{
char buf[1024];
FILE* fp = fopen("abc.c", "r");
if (!fp) // fp == NULL
{
perror("fopen error");
return -1;
}
while (1)
{
memset(buf, 0, 1024);
fgets(buf, 1024, fp); // \n
if (feof(fp))
{
break;
}
printf("%d\n", buf[0]);
}
fclose(fp);
};
int main2301(void)
{
//write_file01();
read_file03();
system("pause");
return EXIT_SUCCESS;
}
int main2302(void)
{
FILE* fp = fopen("test2.txt", "r");
if (!fp) // fp == NULL
{
perror("fopen error");
return -1;
}
int a;
char ch;
char str[10];
int ret = fscanf(fp, "%d %c %s", &a, &ch, str);
printf("ret = %d\n", ret);
fclose(fp);
system("pause");
return EXIT_SUCCESS;
}
练习:文件版排序
生成随机数,写入文件。将文件内乱序随机数读出,排好序再写回文件。
fgetc --- fputc
fgets --- fputs
fprintf -- fscanf 默认处理文本文件。
fwrite()函数,既可以处理文本文件,也处理二进制文件
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
void write_rand()
{
FILE* fp = fopen("test24.txt", "w");
if (!fp) // fp == NULL
{
perror("fopen error");
return -1;
}
srand(time(NULL));
for (size_t i = 0; i < 10; i++)
{
fprintf(fp,"%d\n",rand() % 100);
}
fclose(fp);
}
void BubbleSort(int* src, int len)
{
for (size_t i = 0; i < len - 1; i++)
{
for (size_t j = 0; j < len - 1 - i; j++)
{
if (src[j] > src[j + 1])
{
int temp = src[j];
src[j] = src[j + 1];
src[j + 1] = temp;
}
}
}
}
void rand02()
{
int arr[10], i = 0;
FILE* fp = fopen("test24.txt", "r");
if (!fp) // fp == NULL
{
perror("fopen error");
return -1;
}
while (1)
{
fscanf(fp,"%d\n",&arr[i]);// 从文件中读取一个随机数,存入数组arr存入
i++;
if (feof(fp))
{
break; //先存储后判断,防止数据丢失
}
}
int len = sizeof(arr) / sizeof(arr[0]);
BubbleSort(arr, len);
fclose(fp);
fp = fopen("test24.txt","w");
if (!fp) // fp == NULL
{
perror("fopen error");
return -1;
}
for (size_t i = 0; i < 10; i++)
{
fprintf(fp,"%d\n",arr[i]);
}
fclose(fp);
}
int main24(void)
{
//write_rand();
//getchar();
rand02();
system("pause");
return EXIT_SUCCESS;
}
fwrite()函数
- 写出数据到文件中
- stu_t stu[4] = { ...... };
- size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
- 参数1:待写出的数据的地址
待写出数据大小
- 写出个数
- 文件
- 返回值:成功:永远是参数3的值,通常将2传1,将参数3传实际的字节数
- 失败0
fread()函数
从文件fp 中读取数据
- size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
- 参数1:读取到数据存储的位置
- 参数2:一次读取的字节数
- 参数3:读取的次数
- 参数4:文件
- 返回值:成功参数3 ,返回字节数
- 失败0
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
typedef struct student {
int age;
char name[10];
int num;
} stu_t;
void write_struct()
{
stu_t stu[4] = {
18, "afei", 10,
20, "andy", 20,
30, "lily", 30,
16, "james", 40
};
FILE* fp = fopen("test03.txt", "w");
if (!fp)
{
perror("fopen error");
return -1;
}
int ret = fwrite(&stu[0], 1, sizeof(stu_t) * 4, fp);
if (ret == 0)
{
perror("fwrite error");
return -1;
}
printf("ret = %d\n", ret);
fclose(fp);
}
// 一次读一个元素。
void read_struct()
{
FILE* fp = fopen("test03.txt", "r");
if (!fp)
{
perror("fopen error");
return -1;
}
stu_t s1;
int ret = fread(&s1, 1, sizeof(stu_t), fp);
printf("ret = %d\n", ret);
printf("age = %d, name=%s, num = %d\n", s1.age, s1.name, s1.num);
fclose(fp);
}
// 读所有元素
void read_struct2()
{
FILE* fp = fopen("test03.txt", "r");
if (!fp)
{
perror("fopen error");
return -1;
}
stu_t s1[10]; // stu_t *s1 = malloc(sizeof(stu_t) * 1024);
int i = 0;
while (1)
{
int ret = fread(&s1[i], 1, sizeof(stu_t), fp);
//if (ret == 0) // 替代feof()函数来判断读到文件结尾。
if (feof(fp))
{
break;
}
printf("age = %d, name=%s, num = %d\n", s1[i].age, s1[i].name, s1[i].num);
i++;
}
fclose(fp);
}
int main25_1(void)
{
//write_struct();
read_struct2();
system("pause");
return EXIT_SUCCESS;
}
大文件拷贝
大文件拷贝
- 已知任意类型的文件,对文件复制,产生一个相同新文件
- 打开两个文件,一个‘r’,另一个 ‘w’
- 从r中fread ,fwrite 到w文件中
- 判断到达文件结尾终止
- 关闭
- 注意: 在windows下,打开二进制文件(mp3、mp4、avi、jpg...)时需要使用“b”。如:“rb”、“wb”
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
void myfile_cp()
{
FILE* rfp = fopen("G:\\2.flv","rb");
FILE* wfp = fopen("G:\\mycopy.flv","wb");
char buf[1000000] = {0};//设置缓冲区
int ret = 0;
while (1)
{
memset(buf,0,sizeof(buf));//清除缓冲区
ret = fread(buf,1,sizeof(buf),rfp);
if (ret ==0)
{
break;
}
printf("ret = %d\n",ret);
printf("sizeof%d\n",sizeof(buf));
fwrite(buf,1,ret,wfp);
}
fclose(wfp);
fclose(rfp);
}
int main26(void)
{
myfile_cp();
printf("---------------------------");
system("pause");
return EXIT_SUCCESS;
}
随机位置读:
文件读写指针,在一个文件内只有一个
fseek()
- int fseek(FILE *stream, long offset, int whence);
- 参数1:文件
- 参数2:偏移量(矢量+前后-向前)
- 参数3:
- SEEK_SET 文件开头位置
- SEEK_CUR 当前位置
- SEEK_END文件结尾位置
- 返回值成功0失败-1
ftell()
-
获取文件读写指针位置
-
long ftell(FILE *stream);
-
返回:从文件当前读写位置到起始位置的偏移量
-
借助ftell(FILE*stream)
-
返回:从文件当前读写位置到起始位置偏移量
-
借助 ftell(fp)+fseek(fp,0,SEEK_ENND)来获取文件大小
rewind()
- 回卷文件读写指针,将读写指针移动到起始位置
- void rewind(FILE*stream);
随机读文件
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
typedef struct student
{
int age;
char name[10];
int num;
}stu_t;
int main27(void)
{
stu_t stu[4] = {
18, "afei", 10,
20, "andy", 20,
30, "lily", 30,
16, "james", 40
};
stu_t s1;
FILE* fp = fopen("test05.txt", "wb+");
if (!fp) // fp == NULL
{
perror("fopen error");
return -1;
}
int ret = fwrite(&stu[0],1,sizeof(stu),fp);//以二进制写入
printf("ret = %d\n",ret);
fseek(fp,sizeof(stu_t)*2,SEEK_SET);//从文件起始位置,向后偏移一个结构体
ret = fread(&s1,1,sizeof(s1),fp);
printf("ret = %d\n",ret);
printf("age = %d,name = %s, num = %d\n",s1.age,s1.name,s1.num);
int len = ftell(fp); // 获取文件当前读写指针位置,到文件起始位置的偏移量
printf("len = %d\n",len);
rewind(fp); // 将文件读写指针回卷到开始
ret = fread(&s1,1,sizeof(s1),fp);
printf("ret = %d\n",ret);
printf("age = %d,name = %s, num = %d\n", s1.age, s1.name, s1.num);
//获取文件大小
fseek(fp,0,SEEK_END);//将文件读写指针放到文件结尾
len = ftell(fp);
printf("文件大小 %d\n",len);
fclose(fp);
system("pause");
return EXIT_SUCCESS;
}
LINUX与windows文件区别
- 对于二进制文件操作,windows使用‘b’,Linux二进制和文本没区别
- windows 回车\r 换行 \n \r\n Linux 回车换行 \n
- 对文件指针,先写后读,windows 与Linux效果一样
- 先读后写,Linux无需修改,windoes下需要在写操作之前加入fseek(fp,0,SEEK_CUR)来获取文件读写指针使之3生效
获取文件状态
-
打开文件,对于系统,系统资源消耗较大
-
int stat(const char *path, struct stat *buf);
-
参数1:访问文件路径
-
参数2:文件属性结构体
-
返回值:成功0失败-1
-
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> #include<windows.h> #include <sys/types.h> #include <sys/stat.h> int main30(void) { struct stat buf; int ret = stat("test03.txt",&buf); printf("文件大小:%d\n",buf.st_size); system("pause"); return EXIT_SUCCESS; }
删除重命名文件
- int remove(const char *pathname); 删除文件。
- int rename(const char *oldpath, const char *newpath); 重名文件
缓冲区刷新
标准输出-stdout 标准输出缓冲区,写给屏幕数据都是先存到缓冲区,由缓冲区一次性刷新到物理设备
标准输入 stdin 标准输入到缓冲区,从键盘读取到数据,直接读到缓冲区中,由缓冲区给程序提供数据
- 预读入,缓输出
- 行缓冲:print(); 遇到\n 就会将缓冲区中数据刷新到物理设备上
- 全缓冲:文件,缓冲区存满,数据刷新到物理设备上
- 无缓冲:perror 缓冲区中只要有数据,就会立即刷新到新物理设备
- 文件关闭,缓冲区就会被自动刷新,隐式回收,关闭文件,刷新缓冲区,释放malloc
手动刷新缓冲区:实时刷新
int fflush(FILE *stream);
成功0失败-1
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<windows.h>
int main(void)
{
FILE* fp = fopen("test31.txt", "w+");
if (!fp)
{
perror("fopen error");
return -1;
}
char m = 0;
while (1)
{
scanf("%c",&m);
if (m == ':')
{
break;
}
fputc(m,fp);
fflush(fp);
}
fclose(fp);
system("pause");
return EXIT_SUCCESS;
}
day12
贪吃蛇游戏
- 定义蛇对象,食物对象
- 初始化蛇,初始化食物
- 控制流程
- 蛇头和墙壁碰撞
- 蛇头和蛇身体碰撞
- 蛇头和食物碰撞
- 蛇身增长
- 食物消失
- 新食物产生
- 分数增加
- 移动速度加快
- 蛇移动
- 自动移动
- 手动控制移动 ASWD
- 显示分数
- 图形
1.
贪吃蛇代码
snake.c
#define _CRT_SECURE_NO_WARNINGS
#include "snake.h";
int main(void)
{
CONSOLE_CURSOR_INFO cci;
cci.dwSize = sizeof(cci);
cci.bVisible = FALSE;
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cci);
srand(time(NULL));
initSanke();
initWall();
initFood();
initUI();
playGame();
showScore();
system("pause");
return EXIT_SUCCESS;
}
// 显示分数
void showScore(void)
{
COORD coord;
coord.X = 0;
coord.Y = HIGH +2;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
printf("Game Over!!!\n");
printf("成绩是: %d\n\n\n",score);
}
// 初始化墙
void initWall(void)
{
for (size_t i = 0; i <= HIGH; i++)
{
for (size_t j = 0; j <= WIDE; j++)
{
if (j== WIDE)
{
printf("|");
}
else if (i == HIGH)
{
printf("_");
}
else
{
printf(" ");
}
}
printf("\n");
}
}
// 初始化蛇
void initSanke(void)
{
snake.size = 2;
snake.body[0].X = WIDE / 2; // 蛇头
snake.body[0].Y = HIGH / 2;
snake.body[1].X = WIDE / 2 - 1; // 蛇身
snake.body[1].Y = HIGH / 2;
return;
}
// 初始化食物
void initFood(void)
{
food.X = rand() % WIDE;
food.Y = rand() % HIGH;
return;
}
// 初始化界面
void initUI(void)
{
COORD coord = {0};
// 画蛇
for (size_t i = 0; i < snake.size; i++)
{
coord.X = snake.body[i].X;
coord.Y = snake.body[i].Y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
if (i==0)
{
putchar('@');
}
else
{
putchar('*');
}
}
// 去蛇尾
coord.X = lastX;
coord.Y = lastY;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
putchar(' ');
// 画食物
coord.X = food.X;
coord.Y = food.Y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
putchar('#');
}
// 运行游戏
void playGame(void)
{
char key = 'd';
while (snake.body[0].X >=0 &&
snake.body[0].X <= WIDE &&
snake.body[0].Y >=0 && snake.body[0].Y<= HIGH)// 判断蛇头是否撞墙
{
// 更新蛇
initUI();
// 接收用户按键输入
if (_kbhit())
{
key = _getch(); // 为真说明用户按下按键
}
switch (key)
{
case 'w': kx = 0; ky = -1; break;
case 's': kx = 0; ky = +1; break;
case 'd': kx = +1; ky = 0; break;
case 'a': kx = -1; ky = 0; break;
default:
break;
}
// 蛇头撞身体 蛇头 == 任意一节身体
for (size_t i = 1; i < snake.size; i++)
{
if (snake.body[0].X == snake.body[i].X
&& snake.body[0].Y == snake.body[i].Y)
{
return;
}
}
// 蛇头撞食物
if (snake.body[0].X == food.X && snake.body[0].Y == food.Y)
{
initFood(); // 撞完食物重新生成食物
snake.size++;
score += 10;
sleepSecond -= 10;
}
// 存储蛇尾坐标
lastX = snake.body[snake.size-1].X;
lastY = snake.body[snake.size-1].Y;
// 蛇移动,前一节身体给后一节身体赋值
for (size_t i = snake.size; i >0; i--)
{
snake.body[i].X = snake.body[i - 1].X;
snake.body[i].Y = snake.body[i - 1].Y;
}
snake.body[0].X += kx;
snake.body[0].Y += ky;
Sleep(sleepSecond);
}
return;
}
snake.h
#ifndef __SNAKE_H__
#define __SNAKE_H__
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <conio.h>
#include <Windows.h>
#define WIDE 60
#define HIGH 20
// 身体对象
struct BODY
{
int X;
int Y;
};
// 定义蛇对象
struct SNAKE
{
struct BODY body[WIDE * HIGH];
int size;
}snake; // 蛇对象
struct FOOD
{
int X;
int Y;
}food; // 一个食物对象
int score = 0; // 分数
int kx = 0;
int ky = 0;
int lastX = 0;
int lastY = 0;
int sleepSecond = 100;
// 声明函数
void initSanke(void);
void initFood(void);
void initUI(void);
void playGame(void);
void initWall(void);
void showScore(void);
#endif // !__SNAKE_H__