C语言基础

C语言基础

目录


day01

C语言特点

优点

代码量小

执行速度快

功能强大

编程自由

缺点

写代码实现周期长

可移植性较差

过于自由,经验不足出错

平台库依赖多

计算机结构组成

img

计算机系统组成

image-20220310112932558

C语言关键字

image-20220310120302131

9种控制语句

image-20220310120710360

运算符

image-20220310120748582

#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工具解决

在项目上 -- 属性--配置属性--连接器--系统---子系统--下拉框中控制台

image-20220310170510681

两种编写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

image-20220310181124840

预处理 -E xxx.i 预处理文件

1. 头文件展开,不检查语法错误,可以展开任何文件
1. 宏定义替换 :将宏名替换为宏值
3. 替换注释     : 变成空行
4. 展开条件注释 : 根据条件展开指令
  1. #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 可执行文件

  1. 数据段合并

  2. 数据地址回填

  3. 库引入

image-20220310191040967

C语言可以嵌入汇编

代码调试

打开调试F5,调试 F11

监视,监视变量名的变化

VS快捷键

image-20220310212504281

day02


常量与变量

常量:不会变化的量

  1. ”A”,”hello”,“10”,”1.234567”,””

  2. define PI 3.1415 定义宏 名+值

  3. 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 变量值是表达式

image-20220312175434894

变量的声明:

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

转义字符 ‘\’ 将普通字符转为特殊,反之

转义字符表

image-20220312232506978

实型

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个字符的字符串,不足用空格向左填充

image-20220313094839330

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”)

算术运算

image-20220313113945627

除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);

赋值运算符

image-20220313114005707

int a = 5;

a +=10’

a-=30;

a%=5

比较运算

image-20220313114021245

== 判断是否相等

!= 不等于

<=

=

逻辑运算

image-20220313114037205

运算符优先级

后缀自增高于前缀

sizeof>算术运算>比较运算>逻辑运算>三目运算(条件运算)>赋值运算符>逗号运

三目运算

表达式1 ? 表达式2:表达式3

表达式1是以一个判别表达式,

如果为真,整个三目运算,取值表达式2

如果为假,三目运算取值表达式3

类型转换

由编译器自动完成

由赋值产生的类型转换

隐式类型转换

int r = 3

float s = 3.14 * r * r

由赋值产生的类型转换 ,小转大没问题,大转小可能发生数据丢失

强制目标类型

(目标类型)带转换变量

(目标类型)带转换表达式

大多数用于函数调用期间,实参给形参传值

2016-06-02_202741

分支语句

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,作用

  1. 跳出一重循环

  2. 防止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');
	}


}


image-20220325074618232

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");

}

冒泡排序

image-20220325194841938

#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]);

	数组的首地址 == 数组的首元素地址 == 数组的首行地址。

二维数组初始化

  1. 常规初始化

    int arr[3] [5] = {{2, 3, 54, 56, 7 }, {2, 67, 4, 35, 9}, {1, 4, 16, 3, 78}};
    
  2. 不完全初始化

    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}; 【少见】 系统自动分配行列

  3. 不完全指定行列初始化

  4. 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)
{
}

img

如果程序中需要重复输入大段或常用的代码片段,可使用代码片段管理器自定义代码片段及相应的快捷键,操作步骤如下:

  1. 在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>

按下述步骤将自定义的文件添加到代码片段管理器中

在这里插入图片描述

  1. 此时在VS编辑器中输入cli,按TAB或Enter键,即会自动生成自定义的代码片段;
    在这里插入图片描述
  2. 如果要删除自定义的代码片段,需到指定的位置删除文件。

在这里插入图片描述

多维数组

三维数组 [][][层] [行] [列]

数组类型 数组名 [层] [行] [列]

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. 提高代码复用率
  2. 提高程序模块化

分类

1. 系统库函数,标准C库  libc
 	1. 引入头文件
 	2. 根据函数原型调用
2. 用户自定义
 	1. 除了需要提高函数原型之外,haunt需要提供函数原型实现

随机数

1. 播种随机数种子 srand(time(NULL))
2. 引入头文件 #include <stdlib.h> <time.h>
3. 生成随机数 rand()

函数定义

  1. 包含函数原型(返回值类型,函数名,形参)函数体(大括号,代码实现)

  2. 形参列表,形式参数列表,一定包含,类型名,形参名

  3. int add(int a,int b,int c)

    {

    ​ return a+b+c

    }

函数调用

  1. 包含函数名(实参列表)
  2. ret = add (10,4,28)
  3. 实参,调用时。传参必须按照严格形参填充,(参数个数类型顺序)

函数声明

  1. 函数调用之前,编译必须见过函数定义,否则,需要函数声明
  2. 包函原型(返回值类型,函数名,形参列表)
  3. 隐式声明,不要依赖
    1. 默认编译器做隐式声明函数时,返回都是int,根据调用语句不全函数名和形参列表
  4. 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

image-20220326172155978

头文件

#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;
}

指针与内存单元


指针

内存单元:计算机内存最小的存储单位,内存单元,每一个内存单元都有唯一的一个编号,叫这个内存单元编号是“地址”

image-20220326182330519

指针变量:存地址变量

指针定义和使用

int a = 10;

int *p = &a

*p = 250 指针的解引用,间接引用

*p 将p变量的内容取出,当成地址看待,找到改地址对应的空间

如果做左值,存数据到空间

如果做右值,取出空间中的内容

任意指针类型大小

指针大小与类型无关,只和当前使用的平台架构有关,,32位:4字节,,64位:8字节

野指针

  1. 没有一个有效地址空间指针

  2. int *p

  3. *p = 1000;

  4. image-20220326225949511

  5. p 是一个值,但是不是可访问的内存区域

  6. int *p = 10

  7. *p = 2000;

  8. 杜绝野指针

  9. 	//野指针
    
    	/*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)

image-20220327081511963

指针与数组区别

  1. 指针是变量,数组名是常量
  2. sizeof(指针) 4字节/8字节
  3. 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!!!

指针 +-整数

  1. 普通指针变量 +-整数

char*p 打印p,p+1 偏过1字节

short*p 打印p,p+1 偏过2字节

int *p 打印·p,p+1 偏过4字节

  1. 在数组中 +- 整数

short arr[] = {1,3,5,8}

​ int *p = arr;

​ p+3; // 向右(后)偏过 3 个元素

​ p-2; // 向前(左)偏过 2 个元素

  1. 数组名+1
  2. 加过一个数组大小(数组元素个数x sizeof(数组元素类型))
  3. 指针+-指针:
    1. 指针+指针 :错误
    2. 指针-指针
      1. 普通变量来说,语法允许,无实际意义
      2. 数组来说:偏移过的元素个数


#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函数栈帧内部局部变量值

image-20220329180344700

传址操作

image-20220329183229956



#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区

内存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保存

二级指针

二级指针malloc

二级指针对应的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


结构体

数组:描述一组具有相同类型数据的有序集合,用于处理类型相同的数据的运算

结构体变量定义和初始化

  1. 先声明结构体类型在定义变量名
  2. 在声明类型同时定义变量
  3. 直接定义结构体类型变量(无类型名)

img

结构体类型:指定一个结构体类型,相当于一个模型,但其中并无具体数据,系统对它也不分配实际内存单元

结构体变量:系统根据结构体类型分配空间

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;
}



image-20220331223645922

image-20220331225153096

结构体数组



#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;
}



结构体和指针

image-20220401155354590

image-20220401160411640

在堆中开辟结构体指针

image-20220401161301220



#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

读写

关闭

image-20220401223442136



#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;
}

练习文件版四则运算

  1. 封装write_file 函数,将4则运算表达式写入

  2. 	FILE * fp = fopen("w");
      
      		fputs("10/4=\n", fp);
      
      		fputs("10+4=\n", fp);
      		....
      
      		fputs("10*4=\n", fp);
    
  3. 封装read_file 函数将四则运算表达式独处,拆分运算写回

  4. 读出
    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;
}

大文件拷贝

大文件拷贝

  1. 已知任意类型的文件,对文件复制,产生一个相同新文件
  2. 打开两个文件,一个‘r’,另一个 ‘w’
  3. 从r中fread ,fwrite 到w文件中
  4. 判断到达文件结尾终止
  5. 关闭
  6. 注意: 在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


贪吃蛇游戏

  1. 定义蛇对象,食物对象
  2. 初始化蛇,初始化食物
  3. 控制流程
    1. 蛇头和墙壁碰撞
    2. 蛇头和蛇身体碰撞
    3. 蛇头和食物碰撞
      1. 蛇身增长
      2. 食物消失
      3. 新食物产生
      4. 分数增加
      5. 移动速度加快
  4. 蛇移动
    1. 自动移动
    2. 手动控制移动 ASWD
  5. 显示分数
  6. 图形
    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__

posted @ 2022-03-13 14:15  #卧龙先生#  阅读(178)  评论(0编辑  收藏  举报