Loading

02-C高级编程

Day01

笔记

1	typedef使用
1.1	起别名 -  简化struct关键字
1.2	区分数据类型
1.3	提高代码移植性
2	void使用
2.1	不可以利用void创建变量  无法给无类型变量分配内存
2.2	用途:限定函数返回值,函数参数
2.3	void * 万能指针  可以不通过强制类型转换就转成其他类型指针
3	sizeof用法
3.1	本质:不是一个函数,是一个操作符
3.2	返回值类型 unsigned int无符号整型
3.3	用途:可以统计数组长度
4	变量的修改方式
4.1	直接修改
4.2	间接修改
4.3	对自定义数据类型做练习
5	内存分区
5.1	运行前
5.1.1	代码区   共享  只读
5.1.2	数据区   存放数据:全局变量 、静态变量、常量
5.1.2.1	已初始化数据区  data
5.1.2.2	未初始化数据区  bss
5.2	运行后
5.2.1	栈   符合先进后出数据结构,编译器自动管理分配和释放,有限容量
5.2.2	堆   容量远远大于栈,不是无限。手动开辟 malloc 手动释放 free
6	栈区
6.1	符合先进后出数据结构
6.2	注意事项:不要返回局部变量的地址,局部变量在函数执行之后就被释放了,释放的内存就没有权限取操作了,如果操作结果未知 
7	堆区
7.1	利用malloc在堆区创建数据
7.2	利用free释放堆区
7.3	注意事项:主调函数没有分配内存,被调函数需要用更高级的指针去修饰低级指针,进行分配内存
8	static 和extern 区别
8.1	特点:在运行前分配内存,程序运行结束 生命周期结束  ,在本文件内都可以使用静态变量
8.2	extern 可以提高变量作用域
9	常量
9.1	const修饰的变量
9.1.1	全局变量
9.1.1.1	直接修改 失败 ,间接修改 语法通过,运行失败,受到常量区保护
9.1.2	局部变量
9.1.2.1	直接修改 失败 , 间接修改  成功,放在栈上
9.2	字符串常量
9.2.1	vs 将多个相同字符串常量看成一个
9.2.2	不可以修改字符串常量
9.2.3	ANSI并没有制定出字符串是否可以修改的标准,根据编译器不同,可能最终结果也是不同的
10	

Code

  • 01 typedef使用
//#define _CRT_SECURE_NO_WARNINGS   //VS下使用传统库函数 会建议用_s更安全函数,如果不用会报错误 C4996
#include<stdio.h>   //标准   i input 输入   o  output  输出
#include<string.h>  //对字符串处理  strcat strstr strcmp strcpy
#include<stdlib.h>  //malloc   free



//1、typedef使用  可以简化 struct关键字
//可以起别名
//struct Person
//{
//	char name[64];
//	int age;
//};
//
////语法: typedef  原名   别名
//typedef struct Person  myPerson;


typedef struct Person
{
	char name[64];
	int age;
}myPerson;

void test01()
{
	struct Person p = { "aaa", 10 };

	myPerson p2 = { "bbb", 20 };

}


//2、区分数据类型
void test02()
{
	typedef char * PCHAR;
	PCHAR p1, p2;
	//char *p1, p2;

	char *p3, *p4;
}

//3、提高移植性
typedef int  MYINT;
void test03()
{
	MYINT a = 10;

	MYINT b = 10;

}



//main 函数 程序入口
int main1(){

	//char buf[1024];
	//strcpy(buf, "hello world");
	//printf("%s\n", buf);



	system("pause");  //阻塞  请按任意键继续
	
	return EXIT_SUCCESS; //返回成功退出  0
}
  • 02 void使用.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//1、void 无类型,不可以通过void创建变量,原因无法给void无类型变量分配内存
void test01()
{
	//void  a = 10;
}

//2、用途: 限定函数返回值,限定函数参数
void test02(void)
{
	//return 10;
}

//3、void *   万能指针  不管几级指针,任意类型指针都是4个字节
void test03()
{
	//printf("size of void* = %d\n", sizeof(void *));
	void * p = NULL;

	int * pInt = NULL;
	char * pChar = NULL;

	pChar = (char *)pInt;

	pChar = p; //万能指针  可以不通过强制类型转换就转成其他类型指针

}

int main(){
	
	//test02(10);
	test03();


	system("pause");
	return EXIT_SUCCESS;
}
  • 03 sizeof用法.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//1、sizeof本质  是不是一个函数???不是函数 ,而是 操作符 
void test01()
{
	printf("size of int = %d\n", sizeof(int));

	double d = 3.14;
	
	printf("size of d = %d\n", sizeof d);
}

//2、sizeof 返回值类型 无符号整型 unsigned int
void test02()
{
	//unsigned int a = 10;
	////当unsigned int 和 int做运算,会转换成统一 unsigned int数据类型
	//if (a  - 20 > 0)
	//{
	//	printf("大于0\n");
	//}
	//else
	//{
	//	printf("小于0\n");
	//}

	if ( sizeof(int) - 5 >0)
	{
		printf("大于0\n");
	}
	else
	{
		printf("小于0\n");
	}

}

//sizeof 用途:统计数组长度 , 当数组名做函数参数时候,会退化为指针,指向数组中第一个元素的位置
void calculateArray(int arr[])
{
	printf("array length = %d\n", sizeof(arr));
}

void test03()
{
	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8 };

	calculateArray(arr);
	//printf("array length = %d\n", sizeof(arr));

}

int main(){

	//test01();
	//test02();
	test03();

	

	system("pause");
	return EXIT_SUCCESS;
}
  • 04 变量的修改方式.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//变量的修改方式
void test01()
{
	//1、直接修改
	int a = 10;
	a = 20;

	//2、间接修改 
	int * p = &a;
	*p = 30;
	printf("a = %d\n", a);

}


struct Person
{
	char a; //0 ~ 3
	int b;  //4 ~ 7
	char c; //8 ~ 11
	int d;  //12 ~ 15
};
void test02()
{
	struct Person p = { 'a', 10, 'b', 20 };

	//直接修改 d属性
	p.d = 1000;

	//间接修改 d属性
	//struct Person * pp = &p;
	////pp->d = 1000;

	//printf("%d\n", pp);
	//printf("%d\n", pp+1);


	char * pp = &p;

	*(int*)(pp + 12) = 2000;

	printf("d属性为: %d\n", *(int*)(pp + 12));
	printf("d属性为: %d\n", *(int*)((int*)pp + 3));
}


int main(){
	//test01();
	test02();


	system("pause");
	return EXIT_SUCCESS;
}
  • 05 栈区.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

int * myFunc()
{
	int a = 10;
	return &a;
}

void test01()
{
	//局部变量a早已被释放,因此我们没有权限操作这块内存空间
	int * p = myFunc();
	printf("*p = %d\n", *p);
	printf("*p = %d\n", *p);
}


char * getString()
{
	char str[] = "hello world";
	return str;
}

void test02()
{
	char * p = NULL;
	p = getString();
	printf("%s\n", p);
}



int main(){

	//test01();
	test02();


	system("pause");
	return EXIT_SUCCESS;
}
  • 06 堆区.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

int * getSpace()
{
	int * p = malloc(sizeof(int)* 5);
	if (p == NULL)
	{
		return;
	}
	for (int i = 0; i < 5; i++)
	{
		p[i] = i + 100;
	}
	return p;
}

void test01()
{
	int * p = getSpace();
	for (int i = 0; i < 5; i++)
	{
		printf("%d\n", p[i]);
	}

	//手动开辟  手动释放
	free(p);
	p = NULL;

}


void allocateSpace(char * pp)
{
	char * temp  =  malloc(100);
	memset(temp, 0, 100);
	strcpy(temp, "hello world");
	pp = temp;
}

void test02()
{
	char * p = NULL;
	allocateSpace(p);
	printf("%s\n", p);
}

void allocateSpace2(char ** pp)
{
	char * temp = malloc(100);
	memset(temp, 0, 100);
	strcpy(temp, "hello world");

	*pp = temp;

}

void test03()
{
	char * p = NULL;
	allocateSpace2(&p);
	printf("%s\n", p);

	if (p != NULL)
	{
		free(p);
		p = NULL;
	}
}



int main(){
	//test01();
	//test02();
	test03();
	system("pause");
	return EXIT_SUCCESS;
}
  • 07 static和extern区别
    • test.c
extern int g_a = 1000; //在C语言下  全局变量前都隐式加了关键字 extern
  • 07 static和extern区别.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//static 静态变量
// 特点:在运行前分配内存,程序运行结束 生命周期结束  ,在本文件内都可以使用静态变量
// 全局作用域 a
static int a = 10;

void test01()
{
	//局部作用域 b
	static int b = 20;
}


int main(){

	//告诉编译器 下面代码中出现 g_a 不要报错,是外部链接属性,在其他文件中
	extern int g_a;

	printf("g_a = %d\n", g_a);

	system("pause");
	return EXIT_SUCCESS;
}
  • 08 常量区.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//1、const修饰的变量 
//全局变量
const int a = 10; //常量区 ,间接修改 语法通过,运行失败,原因:受到常量区的保护
void test01()
{
	//a = 100;

	int * p = &a;
	*p = 100;
	printf("%d\n", a);

}

void test02()
{
	const int b = 10; //存放在栈上,通过间接修改是可以成功的

	//b = 20;

	int * p = &b;
	*p = 20;
	printf("%d\n", b);

	//在C语言中 const修饰的局部变量  称为伪常量,不可以初始化数组
	//int arr[b];
}


//2、字符串常量

void test03()
{
	char * p1 = "hello world";
	char * p2 = "hello world";
	char * p3 = "hello world";
	printf("%d\n", &"hello world");
	printf("%d\n", p1);
	printf("%d\n", p2);
	printf("%d\n", p3);
}

void test04()
{
	char * str = "hello world";
	str[0] = 'x';

}

int main(){
	//test01();
	//test02();
	//test03();
	test04();
	system("pause");
	return EXIT_SUCCESS;
}

Day02

笔记

1	宏函数
	1.1	#define  MYADD(x,y)  ((x) + (y)
	1.2	将一些频繁短小的函数  写成宏函数
	1.3	宏函数优点:以空间换时间
	1.4	普通函数有入栈、出栈时间开销
2	函数调用流程
	2.1	局部变量、函数形参、函数返回地址.. 入栈 和 出栈
3	调用惯例
	3.1	主调函数和被调函数必须要有一致约定,才能正确的调用函数,这个约定我们称为调用惯例
	3.2	调用惯例 包含内容: 出栈方、参数传递顺序、函数名称修饰
	3.3	C/C++下默认调用惯例: cdecl   从右到左 ,主调函数管理出栈
4	栈的生长方向和内存存放方向
	4.1	栈生长方向
		4.1.1	栈底  ---  高地址
		4.1.2	栈顶  ---  低地址
	4.2	内存存放方向
		4.2.1	高位字节数据  ---  高地址
		4.2.2	低位字节数据  ---  低地址
		4.2.3	小端对齐方式
5	空指针和野指针
	5.1	空指针
		5.1.1	不能向NULL或者非法内存拷贝数据
	5.2	野指针
		5.2.1	指针变量未初始化
		5.2.2	指针释放后未置空
		5.2.3	指针操作超越变量作用域
	5.3	空指针可以重复释放、野指针不可以重复释放
6	指针的步长
	6.1	+1之后跳跃的字节数
	6.2	解引用 解出的字节数
	6.3	自定义结构体做步长练习
		6.3.1	通过 offsetof( 结构体名称, 属性)  找到属性对应的偏移量
		6.3.2	offsetof 引入头文件 #include<stddef.h>
7	指针的间接赋值
	7.1	三大条件
		7.1.1	一个普通变量+指针变量( 实参+形参)
		7.1.2	建立关系
		7.1.3	通过*  操作内存
	7.2	利用Qt实现 操作地址  修改内存
8	指针做函数参数的输入输出特性
	8.1	输入特性
		8.1.1	在主调函数中分配内存,被调函数使用
		8.1.2	分配在栈上和堆区
	8.2	输出特性
		8.2.1	在被调函数中分配内存,主调函数使用
9	字符串强化训练
	9.1	字符串结束标志 \0
	9.2	sizeof 和 strlen 
	9.3	拷贝字符串 利用三种方式
		9.3.1	利用[]
		9.3.2	利用指针
		9.3.3	while (*dest++ = *src++){}
	9.4	翻转字符串
		9.4.1	利用[ ]
		9.4.2	利用指针
10	sprintf使用
	10.1	格式化字符串
	10.2	sprintf(目标字符串,格式化内容,占位参数…)
	10.3	返回值 有效字符串长度

Code

  • 01 宏函数.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

#define  MYADD(x,y)  ((x) + (y))

//1、宏函数需要加小括号修饰,保证运算的完整性
//2、通常会将频繁、短小的函数  写成宏函数
//3、宏函数 会比普通函数在一定程度上 效率高,省去普通函数入栈、出栈时间上的开销
// 优点: 以空间 换时间


void test01()
{
	printf("%d\n", MYADD(10, 20) * 20 ); //  ((10) + (20)) * 20

}

int main(){
	test01();

	 

	system("pause");
	return EXIT_SUCCESS;
}
  • 02 变量传递分析.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

char * func()
{
	char * p =  malloc(10); //堆区数据,只要没有释放,都可以使用
	int c = 10;//在func中可以使用,test01和main都不可以使用
	return p;
}

void test01()
{
	int b = 10; // 在test01 、func 可以使用,在main中不可以用

	func();
}

int main(){

	int a = 10; //在main 、test01 、 func中都可以使用

	test01();


	system("pause");
	return EXIT_SUCCESS;
}
  • 03 栈的生长方向和内存存放方向.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//1、栈的生长方向
void test01()
{
	int a = 10;  //栈底  高地址
	int b = 10;
	int c = 10;
	int d = 10;  //栈顶  低地址


	printf("%d\n", &a);
	printf("%d\n", &b);
	printf("%d\n", &c);
	printf("%d\n", &d);

}


//2、内存存放方向
void test02()
{
	int a = 0x11223344;

	char * p = &a;

	printf("%x\n", *p);    //44  低位字节数据  低地址
	printf("%x\n", *(p+1)); //33  高位字节数据  高地址
}

int main(){


	//test01();
	test02();
	system("pause");
	return EXIT_SUCCESS;
}
  • 04 空指针和野指针.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//1、不能向NULL或者非法内存拷贝数据
void test01()
{
	//char *p = NULL;
	////给p指向的内存区域拷贝内容
	//strcpy(p, "1111"); //err

	//char *q = 0x1122;
	////给q指向的内存区域拷贝内容
	//strcpy(q, "2222"); //err		

}


//指针操作超越变量作用域
int * doWork()
{
	int a = 10;
	int * p = &a;
	return p;
}

//2、野指针出现情况
void test02()
{
	//2.1 指针变量未初始化
	/*int * p;
	printf("%d\n",*p);*/



	//2.2 指针释放后未置空
	char * str  = malloc(100);
	free(str);
	//记住释放后 置空,防止野指针出现
	//str = NULL;

	//free(str);
	//2.3 空指针可以重复释放、野指针不可以重复释放

	//2.4 指针操作超越变量作用域
	int * p = doWork();
	printf("%d\n", *p);
	printf("%d\n", *p);
}

int main(){
	//test01();
	test02();

	system("pause");
	return EXIT_SUCCESS;
}
  • 05 指针的步长.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <stddef.h> //offsetof的头文件

//1、指针的步长代表 指针+1之后跳跃的字节数
void test01()
{
	char * p = NULL;
	printf("%d\n", p);
	printf("%d\n", p+1);


	double * p2 = NULL;
	printf("%d\n", p2);
	printf("%d\n", p2 + 1);

}

//2、解引用的时候,解出的字节数量
void test02()
{
	char buf[1024] = { 0 };

	int a = 1000;

	memcpy(buf + 1, &a, sizeof(int));

	char * p = buf;
	printf("%d\n", *(int *)(p+1));

}

//步长练习,自定义数据类型练习
struct Person
{
	char a;     // 0 ~ 3
	int b;      // 4 ~ 7
	char buf[64]; // 8 ~ 71
	int d;     // 72 ~ 75
};

void test03()
{
	struct Person p = { 'a', 10, "hello world", 20 };
	
	printf("d属性的偏移量: %d\n", offsetof(struct Person, d));

	printf("d属性的值为:%d\n", *(int *)((char *)&p + offsetof(struct Person, d)));
}

int main(){
	//test01();
	//test02();
	test03();
	system("pause");
	return EXIT_SUCCESS;
}
  • 06 指针的间接赋值.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>


//间接赋值三大条件
// 一个普通变量  和 指针变量   或  一个实参和一个形参
// 建立关系
// * 操作内存

void changeValue(int *a) // int * a = &a2;
{
	*a = 1000;
}

void test01()
{
	int  a = 10;
	int * p = NULL;


	p = &a;

	*p = 100;

	int a2 = 10;
	changeValue(&a2);

	printf("%d\n", a2);
	printf("%d\n", &a2);
}

int main(){
	test01();


	system("pause");
	return EXIT_SUCCESS;
}
  • 07 指针做函数参数的输入输出特性.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//输入特性: 主调函数分配内存,被调函数使用
void func(char * p)
{
	strcpy(p, "hello world");
}

void test01()
{
	//在test01中分配了内存,分配在栈上
	char buf[1024] = { 0 };

	func(buf);

	printf("%s\n", buf);

}

void printString(char * str)
{
	printf("%s\n", str + 6);

}

void test02()
{
	char * p = malloc(sizeof(char)* 64);
	memset(p, 0, 64);
	strcpy(p, "hello world");
	printString(p);

	if (p != NULL)
	{
		free(p);
		p = NULL;
	}
}


//输出特性:在被调函数中分配内存,主调函数使用
void allocateSpace(char ** pp)
{
	char * str = malloc(sizeof(char)* 64);
	memset(str, 0, 64);
	strcpy(str, "helloworld");

	*pp = str;
}
void test03()
{
	char * p = NULL;

	allocateSpace(&p);

	printf("%s\n", p);

}

int main(){

	//test01();
	//test02();
	test03();
	system("pause");
	return EXIT_SUCCESS;
}
  • 08 字符串指针强化训练.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

void test01()
{
	////字符串结束标志位 \0
	//char str1[] = { 'h', 'e', 'l', 'l', 'o' ,'\0'};
	//printf("%s\n", str1);


	//char str2[100] = { 'h', 'e', 'l', 'l', 'o' };
	//printf("%s\n", str2);


	//char str3[] = "hello";
	//printf("%s\n", str3);
	//printf("sizeof str:%d\n", sizeof(str3)); //6
	//printf("strlen str:%d\n", strlen(str3)); //5


	//char str4[100] = "hello";
	//printf("sizeof str:%d\n", sizeof(str4));
	//printf("strlen str:%d\n", strlen(str4));


	//char str5[] = "hello\0world";
	//printf("%s\n", str5);
	//printf("sizeof str5:%d\n", sizeof(str5)); //12
	//printf("strlen str5:%d\n", strlen(str5)); //5


	char str6[] = "hello\012world";
	printf("%s\n", str6);
	printf("sizeof str6:%d\n", sizeof(str6)); //12
	printf("strlen str6:%d\n", strlen(str6)); //11

}


//字符串拷贝实现
//1、利用[] 实现
void copyString01(char * dest , char * src)
{
	int len =strlen(src);
	for (int i = 0; i < len;i++)
	{
		dest[i] = src[i];
	}
	dest[len] = '\0';
}

//2、利用字符串指针
void copyString02(char * dest, char * src)
{
	while (*src != '\0')
	{
		*dest = *src;

		dest++;
		src++;
	}
	*dest = '\0';
}

//3
void copyString03(char * dest, char * src)
{
	while (*dest++ = *src++){}
}

void test02()
{
	char * str = "hello world";
	
	char buf[1024];

	//copyString01(buf, str);
	//copyString02(buf, str);
	copyString03(buf, str);
	printf("%s\n", buf);
}


//字符串翻转
void reverseString01(char * str)
{
	//利用[]
	int len = strlen(str);
	int start = 0;
	int end = len - 1;

	while (start < end)
	{
		char temp = str[start];
		str[start] = str[end];
		str[end] = temp;

		start++;
		end--;
	}

}

void reverseString02(char * str)
{
	int len = strlen(str);
	char * start = str;
	char * end = str + len - 1;

	while (start < end)
	{
		char temp = *start;
		*start = *end;
		*end = temp;
		start++;
		end--;
	}
}

void test03()
{
	char str[] = "abcdefg";

	//reverseString01(str);
	reverseString02(str);
	printf("%s\n",str);
}

int main(){

	//test01();
	//test02();
	test03();

	system("pause");
	return EXIT_SUCCESS;
}
  • 09 sprintf的使用.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

void test01()
{
	char buf[1024];
	//memset(buf, 0, 1024);
	//sprintf(buf, "今天 %d 年 %d月  %d日", 2018, 6, 30);

	//printf("%s\n", buf);


	//2. 拼接字符串
	//memset(buf, 0, 1024);
	//char str1[] = "hello";
	//char str2[] = "world";
	//int len = sprintf(buf, "%s%s", str1, str2); //返回值是字符串长度 不包含\0
	//printf("buf:%s len:%d\n", buf, len);

	//3. 数字转字符串
	//memset(buf, 0, 1024);
	//int num = 100;
	//sprintf(buf, "%d", num);
	//printf("buf:%s\n", buf);


	int num = 100;
	//设置宽度 右对齐
	memset(buf, 0, 1024);
	sprintf(buf, "%8d", num);
	printf("buf:%s\n", buf);
	////设置宽度 左对齐
	memset(buf, 0, 1024);
	sprintf(buf, "%-8d", num);
	printf("buf:%sa\n", buf);
	//转成16进制字符串 小写
	memset(buf, 0, 1024);
	sprintf(buf, "0x%x", num);
	printf("buf:%s\n", buf);

	//转成8进制字符串
	memset(buf, 0, 1024);
	sprintf(buf, "0%o", num);
	printf("buf:%s\n", buf);



}

int main(){

	test01();
		

	system("pause");
	return EXIT_SUCCESS;
}

Day03

笔记

1	calloc 和 realloc
	1.1	calloc 和malloc 都是在堆区分配内存
	1.2	与malloc不同的是,calloc会将空间初始化为0
	1.3	calloc(个数,大小)
	1.4	realloc 重新分配内存
		1.4.1	如果重新分配的内存比原来大,那么不会初始化新空间为0
		1.4.2	先看后续空间,如果足够,那么直接扩展
		1.4.3	如果后续空闲空间不足,那么申请足够大的空间,将原有数据拷贝到新空间下,释放掉原有空间,将新空间的首地址返回
		1.4.4	如果重新分配的内存比原来小,那么释放后序空间,只有权限操作申请空间
2	sscanf的使用
	%*s或%*d	跳过数据
	%[width]s	读指定宽度的数据
	%[a-z]	匹配a到z中任意字符(尽可能多的匹配)
	%[aBc]	匹配a、B、c中一员,贪婪性
	%[^a] 	匹配非a的任意字符,贪婪性
	%[^a-z]	表示读取除a-z以外的所有字符
	2.1	练习 
		2.1.1	将 ip  分别截取到 num1 到 num4中
		2.1.2	将 123456#zhangtao@abcde  中截取中间的zhangtao有效数据
3	查找子串
	3.1	实现mystrstr 自己查找子串功能
4	指针的易错点
	4.1	越界
	4.2	指针叠加会不断改变指针指向
	4.3	返回局部变量地址
	4.4	同一块内存释放多次(不可以释放野指针)
5	const使用场景
	5.1	const使用  修饰形参 防止误操作
6	二级指针做函数参数的输入输出特性
	6.1	二级指针做函数参数的输入特性
		6.1.1	创建在堆区
		6.1.2	创建在栈区
	6.2	二级指针做函数参数的输出特性
		6.2.1	被调函数分配内存,主调函数使用
7	二级指针练习-文件操作
	7.1	读取配置文件信息 ,并且将信息存放到 数组中
	7.2	注意: 释放堆区,关闭文件
8	位运算
	8.1	按位取反  ~  0变1  1 变0
	8.2	按位与  &    全1为1  一0为0
	8.3	按位或  |     全0为0  一1为1
	8.4	按位异或 ^    相同为0   不同为1
9	位移运算
	9.1	左移运算 <<   X  乘以2 ^ X
	9.2	右移运算 >>   X  除以 2 ^X 
		9.2.1	有些机器用0填充高位
		9.2.2	有些机器用1填充高位
		9.2.3	如果是无符号,都是用0填充
10	

Code

  • 01 calloc和realloc.c
//calloc
void test01()
{
	//int * p = malloc(sizeof(int)* 10);

	int * p = calloc(10, sizeof(int)); //calloc 分配在堆区,与malloc不同的是 calloc会初始化数据为0

	for (int i = 0; i < 10;i++)
	{
		printf("%d\n", p[i]);
	}

	if ( p != NULL)
	{
		free(p);
		p = NULL;
	}

}


//realloc  重新分配内存
void test02()
{
	int * p = malloc(sizeof(int)* 10);

	for (int i = 0; i < 10;i++)
	{
		p[i] = i + 100;
	}

	for (int i = 0; i < 10; i++)
	{
		printf("%d\n", p[i]);
	}

	printf("%d\n", p);

	//如果重新分配的内存比原来大,那么不会初始化新空间为0
	p = realloc(p, sizeof(int)* 20);

	printf("%d\n", p);

	for (int i = 0; i < 20; i++)
	{
		printf("%d\n", p[i]);
	}

	//如果重新分配的内存比原来小,那么释放后序空间,只有权限操作申请空间
	p = realloc(p, sizeof(int)* 5);
	printf("%d\n", p);
	printf("%d\n", p[0]);
	printf("%d\n", p[5]);
}




int main(){



	//test01();
	test02();
	system("pause");
	return EXIT_SUCCESS;
}
  • 02 sscanf的使用.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//1、%*s或%*d	跳过数据
void test01()
{
	char * str = "12345abcde";

	char buf[1024] = { 0 };
	sscanf(str, "%*d%s", buf);

	printf("%s\n", buf);

}
void test02()
{
	char * str = "abcde12345"; //忽略遇到空格或者 \t 代表忽略结束

	char buf[1024] = { 0 };

	sscanf(str, "%*[a-z]%s", buf);
	//sscanf(str, "%*s%s", buf);

	printf("%s\n", buf);
}

//%[width]s	读指定宽度的数据
void test03()
{
	char * str = "12345abcde";

	char buf[1024] = { 0 };

	sscanf(str, "%6s", buf);
	printf("%s\n", buf);
}


//%[a-z]	匹配a到z中任意字符(尽可能多的匹配)
void test04()
{
	char * str = "12345abcdeaaa";

	char buf[1024] = { 0 };

	sscanf(str,"%*d%[a-c]", buf); //只要匹配失败,那么就不继续匹配了
	printf("%s\n", buf);

}

void test05()
{
	char * str = "12345abcdeaaa";

	char buf[1024] = { 0 };

	sscanf(str, "%[0-9]", buf); //只要匹配失败,那么就不继续匹配了
	printf("%s\n", buf);
}

//%[aBc]	匹配a、B、c中一员,贪婪性
void test06()
{
	char * str = "abcCdef";
	char buf[1024] = { 0 };

	sscanf(str, "%[abC]", buf); //只要匹配失败,那么就不继续匹配了
	printf("%s\n", buf);
}


//%[^a] 	匹配非a的任意字符,贪婪性
void test07()
{
	char * str = "abcCdef";
	char buf[1024] = { 0 };

	sscanf(str, "%[^C]", buf); 
	printf("%s\n", buf);

}


//%[^a-z]	表示读取除a-z以外的所有字符
void test08()
{
	char * str = "abcCdef123456";
	char buf[1024] = { 0 };

	sscanf(str, "%[^0-9]", buf);
	printf("%s\n", buf);
}


//练习1
void test09()
{
	char * ip = "127.0.0.1";

	int num1 = 0;
	int num2 = 0;
	int num3 = 0;
	int num4 = 0;

	sscanf(ip, "%d.%d.%d.%d", &num1, &num2, &num3, &num4);

	printf("%d\n", num1);
	printf("%d\n", num2);
	printf("%d\n", num3);
	printf("%d\n", num4);

}

//练习2
void test10()
{
	char * str = "abcdef#zhangtao@123456";

	char buf[1024] = { 0 };

	sscanf(str, "%*[^#]#%[^@]", buf);

	printf("%s\n", buf);

}

//1.	已给定字符串为: helloworld@itcast.cn,请编码实现helloworld输出和itcast.cn输出。
void test11()
{
	char * str = "helloworld@itcast.cn";

	char buf1[1024] = { 0 };
	char buf2[1024] = { 0 };

	sscanf(str, "%[a-z]%*[@]%s", buf1, buf2);

	printf("%s\n", buf1);
	printf("%s\n", buf2);

}


int main(){

	//test01();
	//test02();
	//test03();
	//test04();
	//test05();
	//test06();
	//test07();
	//test08();
	//test09();
	//test10();
	test11();
	system("pause");
	return EXIT_SUCCESS;
}
  • 03 查找子串.c
/*
	算法优化
	memcmp(str , subStr ,3 ) == 0;
*/
int myStrstr(char * str , char * subStr)
{
	int num = 0;
	while (*str != '\0')
	{
		if (*str != *subStr)
		{
			num++;
			str++;
			continue;
		}

		//创建两个临时指针 做二次对比
		char * tmpStr = str;
		char * tmpSubstr = subStr;

		while (*tmpSubstr != '\0')
		{
			if (*tmpStr != *tmpSubstr)
			{
				//匹配失败
				num++;
				str++;
				break;
			}
			tmpStr++;
			tmpSubstr++;
		}
		if (*tmpSubstr == '\0')
		{
			//匹配成功
			return num;
		}

	}

	return -1;
}

void test01()
{
	char * str = "abdnfcdefgdfasdfaf";

	int ret = myStrstr(str, "dnf");

	if ( ret != -1)
	{
		printf("找到了子串,位置为:%d\n", ret);
	}
	else
	{
		printf("未找到子串\n");
	}

}


int main(){
	test01();


	system("pause");
	return EXIT_SUCCESS;
}
  • 04 指针易错点.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

void test01()
{
	char * p = malloc(sizeof(char)* 64);
	char * pp = p; //通过创建临时指针操作内存,防止出错
	for (int i = 0; i < 10;i++)
	{
		*pp = i + 97;
		printf("%c\n", *pp);
		pp++; //更改指针位置,释放出错
	}

	if (p!= NULL)
	{
		free(p);
	}


}

int main(){
	test01();


	system("pause");
	return EXIT_SUCCESS;
}
  • 05 const的使用场景.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

struct Person
{
	char name[64]; // 0 ~ 63
	int age; // 64 ~ 67
	int Id;  // 68 ~ 71
	double score; // 72 ~79
};

//将struct Person p 改为 struct Person * p  节省资源
//const使用  修饰形参 防止误操作
void showPerson(const struct Person *p)
{
	//p.age = 100;
	//p->age = 100;
	//printf("姓名: %s  年龄: %d  学号 %d  分数 %f\n", p.name, p.age, p.Id, p.score);
	printf("姓名: %s  年龄: %d  学号 %d  分数 %f\n", p->name, p->age, p->Id, p->score);
}

void test01()
{
	struct Person p = { "Tom", 18, 1, 60 };

	showPerson(&p);
	
}

int main(){

	test01();

	system("pause");
	return EXIT_SUCCESS;
}
  • 06 二级指针做函数参数的输入特性.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

void printArray(int ** pArray , int len)
{
	for (int i = 0; i < len;i++)
	{
		printf("%d\n", *pArray[i]);
	}

}

void test01()
{
	//创建在堆区
	int ** pArray = malloc(sizeof(int *)* 5);

	//在栈上创建5个数据
	int a1 = 10;
	int a2 = 20;
	int a3 = 30;
	int a4 = 40;
	int a5 = 50;

	pArray[0] = &a1;
	pArray[1] = &a2;
	pArray[2] = &a3;
	pArray[3] = &a4;
	pArray[4] = &a5;

	//打印数组
	printArray(pArray, 5);

	//释放堆区数据
	if (pArray != NULL)
	{
		free(pArray);
		pArray = NULL;
	}

}

void freeSpace(int **pArray , int len)
{
	for (int i = 0; i < len;i++)
	{
		free(pArray[i]);
		pArray[i] = NULL;
	}

}

void test02()
{
	//创建在栈区
	int * pArray[5];

	for (int i = 0; i < 5;i++)
	{
		pArray[i] = malloc(4);
		*(pArray[i]) = 10 + i;
	}

	printArray(pArray, 5);

	//释放堆区
	freeSpace(pArray,5);

}

int main(){

	//test01();
	test02();

	system("pause");
	return EXIT_SUCCESS;
}
  • 07 二级指针做函数参数的输出特性.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>


void allocateSpace(int ** p)
{
	int *  temp = malloc(sizeof(int)* 10);
	for (int i = 0; i < 10;i++)
	{
		temp[i] = 100 + i;
	}
	*p = temp;

}

void printArray(int ** pArray, int len)
{
	for (int i = 0; i < len;i++)
	{
		printf("%d\n", (*pArray)[i]);
	}
}

void freeSpace(int ** pArray)
{
	if (*pArray != NULL)
	{
		free(*pArray);
		*pArray = NULL;
	}
}

void test01()
{
	int * p = NULL;
	allocateSpace(&p);

	printArray(&p, 5);

	freeSpace(&p, 5);
	
	if (p == NULL)
	{
		printf("空指针\n");
	}
	else
	{
		printf("野指针\n");
	}
}

int main(){
	test01();


	system("pause");
	return EXIT_SUCCESS;
}
  • 08 二级指针练习-文件读写.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//获取有效行数
int getFileLines(FILE * pFile)
{
	if (pFile == NULL)
	{
		return -1;
	}

	char buf[1024] = { 0 };
	int lines = 0;
	while (fgets(buf,1024,pFile) != NULL)
	{
		//printf("%s", buf);
		lines++;
	}

	//将文件光标置首
	fseek(pFile, 0, SEEK_SET);
	return lines;

}

//读取数据放入到pArray中
void readFileData(FILE * pFile, int len, char ** pArray)
{
	if (pFile == NULL)
	{
		return;
	}
	if (len <= 0 )
	{
		return;
	}
	if ( pArray ==NULL)
	{
		return;
	}
	char buf[1024] = { 0 };
	int index = 0;
	while (fgets(buf, 1024, pFile) != NULL)
	{
		/*
		aaaaaaaaaa
		bbbb
		cccccc
		*/
		int currentLen = strlen(buf) +1 ;
		char * currentStrP = malloc(sizeof(char)* currentLen);
		strcpy(currentStrP, buf);
		pArray[index++] = currentStrP;

		memset(buf, 0, 1024);
	}

}

void showFileData(char ** pArray, int len)
{
	for (int i = 0; i < len;i++)
	{
		printf("%d行的数据为 %s", i + 1, pArray[i]);
	}
	
}

void test01()
{
	//打开文件
	FILE * pFile =	fopen("./test.txt", "r");
	if (pFile == NULL)
	{
		printf("文件打开失败\n");
		return;
	}

	//统计有效行数
	int len =  getFileLines(pFile);
	//printf("文件的有效行数为:%d\n", len);
	char ** pArray =  malloc(sizeof(char *)* len);

	//读取文件中的数据并且放入到 pArray中
	readFileData(pFile, len, pArray);

	//读取数据
	showFileData(pArray , len);

	//释放堆区内容
	for (int i = 0; i < len; i++)
	{
		if (pArray[i] != NULL)
		{
			free(pArray[i]);
			pArray[i] = NULL;
		}
	}
	free(pArray);
	pArray = NULL;
	//关闭文件
	fclose(pFile);
}

int main(){


	test01();


	system("pause");
	return EXIT_SUCCESS;
}
  • 09 位运算.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//按位取反 ~
void test01()
{
	int num = 2;

	// 010 取反
	// 101 源码
	//计算机用补码方式存数据  110 + 1      =  111

	printf("~num = %d\n", ~num); // -3

}

//按位与 &
void test02()
{
	int num = 123;
	if (  (num & 1 ) == 1 )
	{
		printf("num为奇数\n");
	}
	else
	{
		printf("num为偶数\n");
	}

}

//按位或 |
void test03()
{
	int num1 = 5;
	int num2 = 3;
	printf("num1 | num2 =  %d\n", num1 | num2); // 7

}

//按位异或  ^
void test04()
{
	int num1 = 5;
	int num2 = 9;

	/*int tmp = num1;
	num1 = num2;
	num2 = tmp;*/

	num1 = num1 ^ num2;
	num2 = num1 ^ num2;
	num1 = num1 ^ num2;


	//num1 = num1 + num2;
	//num2 = num1 - num2;
	//num1 = num1 - num2;


	printf("num1 = %d\n", num1);
	printf("num2 = %d\n", num2);

}

//左移运算 << 
void test05()
{
	int num = 20;  // 20 * 2 ^ 2;
	printf("%d\n", num <<= 2);
}
//右移运算 >>
void test06()
{
	int num = 20;  // 20 / 2
	printf("%d\n", num >>= 1);
}

int main(){

	//test01();
	//test02();
	//test03();
	//test04();
	//test05();
	test06();
	system("pause");
	return EXIT_SUCCESS;
}

Day04

笔记

1	一维数组名
	1.1	除了两种特殊情况外,都是指向数组第一个元素的指针
		1.1.1	特殊情况1   sizeof 统计数组长度   
		1.1.2	特殊情况2   对数组名取地址,数组指针,步长整个数组长度
	1.2	数组名是指针常量,指针的指向不可以修改的,而指针指向的值可以改
	1.3	传参数时候,int arr[]  可读性更高
	1.4	数组索引下标可以为负数
2	数组指针的定义方式
	2.1	先定义出数组类型,再通过类型定义数组指针变量
		2.1.1	typedef int(ARRARY_TYPE)[5];  //ARRARY_TYPE 代表存放5个int类型元素的数组 的数组类型
	2.2	先定义数组指针类型,再通过类型定义数组指针变量
		2.2.1	typedef int(*ARRARY_TYPE)[5];
	2.3	直接定义数组指针变量
		2.3.1	int(* p )[5] = &arr;
3	二维数组名
	3.1	二维数组名 除了两种特殊情况外,是指向第一个一维数组的 数组指针
	3.2	两种特殊情况
		3.2.1	sizeof 统计二维数组大小
		3.2.2	对数组名称取地址  int(*p)[3][3] = &arr
	3.3	二维数组做函数参数
		3.3.1	//void printArray(int (*array)[3], int row, int col)
		3.3.2	//void printArray(int array[][3], int row ,int col)
		3.3.3	void printArray(int array[3][3], int row ,int col)  可读性比较高
	3.4	数组指针 和  指针数组?
		3.4.1	数组指针: 指向数组的指针
		3.4.2	指针数组: 由指针组成数组 
4	指针数组排序
	4.1	选择排序
		4.1.1	例如从小到大
		4.1.2	开始认定最小值下标为i,从j = i+1的位置起找真实最小值下标,如果计算的真实最小值下标与i不等,互换元素
	4.2	利用选择排序实现 指针数组 从大到小排序
		4.2.1	字符串对比
		4.2.2	if ( strcmp(pArr[max],pArr[j]) == -1)
5	结构体基本概念
	5.1	加typedef 可以给结构体起别名
	5.2	不加typedef ,可以直接创建一个结构体变量
	5.3	结构体声明 可以是匿名
	5.4	在栈上创建和在堆区创建结构体
	5.5	在栈上和堆区创建结构体变量数组
6	结构体深浅拷贝
	6.1	系统提供的赋值操作是 浅拷贝 – 简单值拷贝,逐字节拷贝
	6.2	如果结构体中有属性 创建在堆区,就会出现问题,在释放期间,一段内存重复释放,一段内存泄露
	6.3	解决方案:自己手动去做赋值操作,提供深拷贝
7	结构体嵌套一级指针练习
	7.1	在堆区创建一个 结构体指针数组
		7.1.1	malloc(sizeof(struct Person *) *3 )
	7.2	在堆区创建出结构体变量
		7.2.1	malloc(sizeof(struct Person))
	7.3	在堆区创建出具体姓名
		7.3.1	malloc(sizeof(char )*64);
	7.4	打印数据
	7.5	释放数组

Code

  • 01 一维数组名.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
// int arr[]  可读性更高
void printArray(int arr[] , int len) //int arr[]等价于  int * arr
{
	for (int i = 0; i < len;i++)
	{
		printf("%d\n", arr[i]);
	}
}

void test01()
{

	//一维数组名是不是指针?
	int arr[5] = { 1, 2, 3, 4, 5 };

	printf("%d\n", sizeof(arr));

	//有两种特殊情况,一维数组名不是 指向第一个元素的指针
	//1、sizeof
	//2、对数组名取地址   得到数组指针 步长是整个数组长度

	
	//printf("%d\n", &arr);
	//printf("%d\n", &arr + 1);
	
	//int * p =  arr;
	int len = sizeof(arr) / sizeof(int);
	printArray(arr, len);

	//arr数组名  它是一个指针常量 指针的指向不可以修改的,而指针指向的值可以改 int * const a ; 
	//arr[0] = 1000;
	//arr = NULL;

	//数组索引 可不可以为负数   答案:可以
	int * p = arr;
	p = p + 3;
	printf("%d\n",p[-1]);     //给人看的
	printf("%d\n", *(p - 1)); //给机器看的
}

int main(){

	test01();

	system("pause");
	return EXIT_SUCCESS;
}
  • 02 数组指针的定义方式.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//数组指针的定义方式
//1、先定义数组类型,再通过类型定义数组指针
void test01()
{
	int arr[5] = { 1, 2, 3, 4, 5 };

	typedef int(ARRARY_TYPE)[5];//ARRARY_TYPE 代表存放5个int类型元素的数组 的数组类型
	
	/*ARRARY_TYPE arr2;
	for (int i = 0; i < 5;i++)
	{
		arr2[i] = 100 + i;
	}
	for (int i = 0; i < 5; i++)
	{
		printf("%d\n", arr2[i]);
	}*/

	ARRARY_TYPE * arrP = &arr;
	// *arrP == arr == 数组名
	for (int i = 0; i < 5;i++)
	{
		printf("%d\n", (*arrP)[i]);
	}

}

void test02()
{
	//先定义数组指针类型,再通过类型定义数组指针
	int arr[5] = { 1, 2, 3, 4, 5 };

	typedef int(*ARRARY_TYPE)[5];

	ARRARY_TYPE arrP = &arr;

	for (int i = 0; i < 5; i++)
	{
		printf("%d\n", (*arrP)[i]);
	}

}

void test03()
{
	//直接定义数组指针变量

	int arr[5] = { 1, 2, 3, 4, 5 };

	int(* p )[5] = &arr;

	for (int i = 0; i < 5;i++)
	{
		printf("%d\n", (*p)[i]);
	}

}

int main(){

	//test01();
	//test02();
	test03();
	system("pause");
	return EXIT_SUCCESS;
}
  • 03 二维数组名.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

void test01()
{
	//可读性高
	int arr[3][3] = {
		{1,2,3},
		{4,5,6},
		{7,8,9}
	};

	/*int arr2[3][3] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	int arr3[][3] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };*/


	//除了两种特殊情况外 ,二维数组名称是 指向第一个一维数组  数组指针
	//特殊情况1  sizeof
	//特殊情况2  对数组名取地址 &arr  获取的是二维数组的 数组指针 int(*p)[3][3] = &arr;
	//printf("%d\n", sizeof(arr));

	int(*pArray)[3] = arr;

	//访问二维数组中的 6 这个元素
	printf("%d\n", arr[1][2]);  //给人看
	printf("%d\n", *(*(pArray + 1) + 2)); //给机器看

}


//void printArray(int (*array)[3], int row, int col)
//void printArray(int array[][3], int row ,int col)
void printArray(int array[3][3], int row ,int col) //array[3][3] 等价于 一维数组指针   int (*array)[3]
{
	for (int i = 0; i < row; i ++)
	{
		for (int j = 0; j < col;j ++)
		{
			//printf("%d ", array[i][j]);
			printf("%d ", *(*(array + i) + j));
		}
		printf("\n");
	}
}

//二维数组做函数参数
void test02()
{
	int arr[3][3] = {
		{ 1, 2, 3 },
		{ 4, 5, 6 },
		{ 7, 8, 9 }
	};

	printArray(arr, 3, 3);

}

int main(){

	//test01();
	test02();
	system("pause");
	return EXIT_SUCCESS;
}
  • 04 指针数组排序.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

void mySort(int arr[] , int len)
{

	for (int i = 0; i < len;i++)
	{
		int min = i; //记录最小值的下标为i
		for (int j = i + 1; j < len;j++)
		{
			if (arr[min]> arr[j])
			{
				//更新真实最小值下标
				min = j;
			}
		}
		//判断真实最小值下标 是否与开始认定的i相等,如果不等,交换元素
		if (i != min)
		{
			int temp = arr[i];
			arr[i] = arr[min];
			arr[min] = temp;
		}
	}

}

void printArray(int arr[], int len)
{
	for (int  i = 0; i < len; i++)
	{
		printf("%d\n", arr[i]);
	}
}

void test01()
{
	//从小到大 排序 利用选择排序
	int arr[] = { 2, 5, 1, 3, 4 };

	int len = sizeof(arr) / sizeof(int);
	mySort(arr, len);

	printArray(arr, len);

}

//void selectSort(char ** pArr, int len)
void selectSort(char * pArr[] , int len)
{
	for (int i = 0; i < len;i++)
	{
		int max = i;
		for (int j = i + 1; j < len;j++)
		{
			//if (pArr[max] < pArr[j])
			if ( strcmp(pArr[max],pArr[j]) == -1)
			{
				max = j;
			}
		}
		if ( i != max)
		{
			char * tmp = pArr[i];
			pArr[i] = pArr[max];
			pArr[max] = tmp;
		}
	}

}

void printArray2(char ** pArr, int len)
{
	for (int i = 0; i < len;i++)
	{
		printf("%s\n", pArr[i]);
	}
}

void test02()
{
	//对指针数组进行排序,排序的算法利用 选择排序   从大到小
	char * pArray[] = { "aaa", "fff", "bbb", "ddd", "ccc", "eee" };

	int len = sizeof(pArray) / sizeof(char*);
	selectSort(pArray, len);

	printArray2(pArray, len);
}

int main(){
	//test01();
	test02();

	system("pause");
	return EXIT_SUCCESS;
}
  • 05 结构体的基本使用.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//struct Person
//{
//	char name[64];
//	int age;
//};
//typedef struct Person myPerson;

typedef struct Person
{
	char name[64];
	int age;
}myPerson;

void test01()
{
	struct Person p = { "Tom", 18 };
	myPerson p2 = { "Jerry", 20 };
}


struct Person2
{
	char name[64];
	int age;
}myPerson2 = { "aaa", 20 };

void test02()
{
	printf("姓名:%s 年龄%d\n", myPerson2.name, myPerson2.age);
}

//匿名结构体
struct 
{
	char name[64];
	int age;
}myPerson3 = { "bbb", 30 };

void test03()
{
	printf("姓名:%s 年龄%d\n", myPerson3.name, myPerson3.age);
}

//结构体创建
void test04()
{
	//创建在栈上
	struct Person p = { "aaa", 10 };

	printf("姓名:%s  年龄: %d\n", p.name, p.age);

	//创建在堆区
	struct Person * p2 = malloc(sizeof(struct Person));
	strcpy(p2->name, "bbb");
	p2->age = 20;

	printf("姓名:%s  年龄: %d\n", p2->name, p2->age);

	if (p2 != NULL)
	{
		free(p2);
		p2 = NULL;
	}
}


void printArray( struct Person personArray[]  ,int len)
{
	for (int i = 0; i < len;i++)
	{
		printf("姓名 : %s ,年龄 : %d \n", personArray[i].name, personArray[i].age);
	}
}
//结构体变量数组创建
void test05()
{
	//在栈上分配内存
	struct Person persons[] =
	{
		{ "aaa", 10 },
		{ "bbb", 20 },
		{ "ccc", 30 },
		{ "ddd", 40 },
	};
	int len = sizeof(persons) / sizeof(struct Person);
	//printArray(persons, len);


	//在堆区分配内存
	struct Person * pArray = malloc(sizeof(struct Person) * 4);
	for (int i = 0; i < 4;i++)
	{
		sprintf(pArray[i].name, "name_%d", i + 1);
		pArray[i].age = 18 + i;
	}
	
	printArray(pArray, 4);

	if (pArray != NULL)
	{
		free(pArray);
		pArray = NULL;
	}

}


int main(){
	//test02();
	//test03();
	//test04();
	test05();


	system("pause");
	return EXIT_SUCCESS;
}
  • 06 结构体深浅拷贝.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

struct Person
{
	char name[64];
	int age;
};

void test01()
{
	struct Person p1 = { "Tom", 18 };

	struct Person p2 = { "Jerry", 20 };

	p1 = p2;

	printf("p1的姓名:%s  年龄 :%d\n", p1.name, p1.age);

	printf("p2的姓名:%s  年龄 :%d\n", p2.name, p2.age);

}



struct Person2
{
	char * name;

	int age;
};


void test02()
{
	struct Person2 p1;
	p1.name = malloc(sizeof (char)* 64);
	strcpy(p1.name, "Tom");
	p1.age = 18;

	struct Person2 p2;
	p2.name = malloc(sizeof (char)* 128);
	strcpy(p2.name, "Jerry");
	p2.age = 28;

	//p1 = p2; //系统提供的赋值操作是简单的浅拷贝 ,我们需要做手动赋值,提供深拷贝

	//////// 手动赋值 ////////
	//先释放原来堆区的内容
	if (p1.name != NULL)
	{
		free(p1.name);
		p1.name = NULL;
	}
	//在堆区创建内存
	p1.name = malloc(strlen(p2.name) + 1);
	strcpy(p1.name, p2.name);
	p1.age = p2.age;

	////////////////////

	printf("p1的姓名:%s  年龄 :%d\n", p1.name, p1.age);

	printf("p2的姓名:%s  年龄 :%d\n", p2.name, p2.age);


	if (p1.name != NULL)
	{
		free(p1.name);
		p1.name = NULL;
	}

	if (p2.name != NULL)
	{
		free(p2.name);
		p2.name = NULL;
	}

}

int main(){

	//test01();
	test02();


	system("pause");
	return EXIT_SUCCESS;
}
  • 07 结构体嵌套一级指针练习.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

struct Person
{
	char * name;
	int age;
};

struct Person ** allocateSpace()
{
	struct Person ** temp = malloc(sizeof(struct Person *) * 3);

	for (int i = 0; i < 3;i++)
	{
		//创建结构体内存
		temp[i] = malloc(sizeof(struct Person));

		//将结构体姓名 创建在堆区 
		temp[i]->name = malloc(sizeof(char)* 64);

		//给姓名赋值
		sprintf(temp[i]->name, "name_%d", i + 1);

		temp[i]->age = 18 + i;
	}


	return temp;
}

void printPerson(struct Person ** pArray, int len)
{
	for (int i = 0; i < len;i++)
	{
		printf("姓名: %s 年龄: %d\n", pArray[i]->name, pArray[i]->age);
	}


}

void freeSpace(struct Person ** pArray , int len)
{
	if ( pArray == NULL)
	{
		return;
	}
	if (len <= 0)
	{
		return;
	}

	for (int i = 0; i < 3;i++)
	{
		if (pArray[i]->name != NULL)
		{
			printf("%s被释放了\n", pArray[i]->name);
			free(pArray[i]->name);
			pArray[i]->name = NULL;
		}

		free(pArray[i]);
		pArray[i] = NULL;
	}

	free(pArray);
	pArray = NULL;
}

void test01()
{
	struct Person ** pArray = NULL;

	pArray = allocateSpace();


	//打印数组
	printPerson(pArray, 3);

	//释放内存
	freeSpace(pArray,3);
	pArray = NULL;
}

int main(){
	test01();


	system("pause");
	return EXIT_SUCCESS;
}

Day05

Code

  • 01 结构体嵌套二级指针练习.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

struct Teacher
{
	char * name;
	char ** students;
};

void allocateSpace(struct Teacher*** teachers)
{
	if (teachers == NULL)
	{
		return;
	}

	//开辟内存
	struct Teacher ** ts =  malloc(sizeof(struct Teacher *) * 3);

	//给每个老师分配内存
	for (int i = 0; i < 3;i++)
	{
		ts[i] = malloc(sizeof(struct Teacher));


		//给老师的姓名分配内存
		ts[i]->name = malloc(sizeof(char)* 64);

		//给老师起名称
		sprintf(ts[i]->name, "Teacher_%d", i + 1);


		//给学生的数组分配内存
		ts[i]->students = malloc(sizeof(char *)* 4);

		//给学生的姓名开辟内存 以及赋值
		for (int j = 0; j < 4;j++)
		{
			ts[i]->students[j] = malloc(sizeof(char)* 64);
			sprintf(ts[i]->students[j], "%s_Student_%d", ts[i]->name, j + 1);
		}
	}

	*teachers = ts;
}

void printTeachers(struct Teacher** pArray)
{
	if (pArray == NULL)
	{
		return;
	}

	for (int i = 0; i < 3;i++)
	{
		printf("%s\n", pArray[i]->name);
		for (int j = 0; j < 4;j++)
		{
			printf("      %s\n", pArray[i]->students[j]);
		}
	}

}

void freeSpace(struct Teacher ** pArray)
{
	if (pArray == NULL)
	{
		return;
	}

	for (int i = 0; i < 3;i++)
	{
		//先释放老师姓名
		if (pArray[i]->name != NULL)
		{
			free(pArray[i]->name);
			pArray[i]->name = NULL;
		}

		//释放学生姓名
		for (int j = 0; j < 4;j++)
		{
			if (pArray[i]->students[j] != NULL)
			{
				free(pArray[i]->students[j]);
				pArray[i]->students[j] = NULL;
			}
		}
		//释放学生的数组
		if (pArray[i]->students != NULL)
		{
			free(pArray[i]->students);
			pArray[i]->students = NULL;
		}

		//释放老师
		if (pArray[i] != NULL)
		{
			free(pArray[i]);
			pArray[i] = NULL;
		}

	}


	//释放老师数组
	if (pArray != NULL)
	{
		free(pArray);
		pArray = NULL;
	}

}

void test01()
{
	struct Teacher ** pArray = NULL;
	//开辟内存
	allocateSpace(&pArray);

	//打印数组
	printTeachers(pArray);

	//释放数组
	freeSpace(pArray);
	pArray = NULL;

}


int main(){

	test01();

	system("pause");
	return EXIT_SUCCESS;
}
  • 02 结构体偏移量.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <stddef.h>

struct Teacher
{
	char a; //0 ~ 3
	int b;  //4 ~ 7
};

void test01()
{

	struct Teacher t1;
	struct Teacher *p = &t1;

	printf("b的属性偏移量为:%d\n", (int)&(p->b) - (int)p);

	printf("b的属性偏移量为:%d\n", offsetof(struct Teacher, b));

}

//通过偏移量 操作内存
void test02()
{
	struct Teacher t1 = { 'a', 10 };

	printf("t1.b = %d\n", *(int *)((char *)&t1 + offsetof(struct Teacher, b)));

	printf("t1.b = %d\n", *(int *)((int *)&t1 + 1 ));

}


struct Teacher2
{
	char a;
	int b;
	struct Teacher c;
};

void test03()
{
	struct Teacher2 t1 = { 'a', 10, 'b', 20 };

	int offset1 = offsetof(struct Teacher2, c);
	int offset2 = offsetof(struct Teacher, b);

	printf("%d\n", *(int*)((char*)&t1 + offset1 + offset2));


	printf("%d\n",   (( struct Teacher * )((char*)&t1 +offset1))->b  );

}

int main(){
	//test01();
	//test02();
	test03();
	system("pause");
	return EXIT_SUCCESS;
}
  • 03 内存对齐.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

#pragma pack(show) //查看当前对齐模数 ,对齐模数是可以改的,改成2的N次方

//第一个属性开始  从0开始偏移
//第二个属性开始  要放在 该类型的大小  与  对齐模数比  取小的值  的整数倍
//所有属性都计算完后,再整体做二次偏移,将整体计算的结果 要放在  结构体最大类型 与对齐模数比  取小的值的 整数倍上

typedef struct _STUDENT{

	int a;    //0 ~ 3      0 ~ 3
	char b;   //4 ~ 7      4
	double c; //8 ~ 15     5 ~ 12
	float d;  //16 ~ 19    13 ~ 16
}Student;


void test01()
{
	printf("sizeof  student  = %d\n", sizeof(Student));

}

//结构体嵌套结构体时候,子结构体放在该结构体中最大类型 和对齐模数比 的整数倍上即可
typedef struct _STUDENT2{
	char a;  // 0 ~ 7
	Student b; // 8  ~ 31
	double c;  //32 ~ 39
}Student2;

void test02()
{
	printf("sizeof  student  = %d\n", sizeof(Student2));
}


int main(){
	//test01();
	test02();

	system("pause");
	return EXIT_SUCCESS;
}
  • 04 文件读写回顾.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//按照字符读写文件:fgetc(), fputc()

void test01()
{
	//写文件

	FILE * f_write = fopen("./test01.txt", "w+");

	if (f_write == NULL)
	{
		return;
	}

	char buf[] = "this is first test";
	for (int i = 0; i < strlen(buf);i++)
	{
		fputc(buf[i], f_write);
	}

	fclose(f_write);

	//读文件
	FILE * f_read = fopen("./test01.txt", "r");
	if (f_read == NULL)
	{
		return;
	}
	char ch;
	while ( (ch = fgetc(f_read)) != EOF  )  // EOF  Enf of File
	{
		printf("%c", ch);
	}
	fclose(f_read);
}


//按照行读写文件:fputs(), fgets()
void test02()
{
	//写文件
	FILE * f_write = fopen("./test02.txt", "w");
	if (f_write == NULL)
	{
		return;
	}
	char * buf[] =
	{
		"锄禾日当午\n",
		"汗滴禾下土\n",
		"谁知盘中餐\n",
		"粒粒皆辛苦\n",
	};

	for (int i = 0; i < 4;i++)
	{
		fputs(buf[i], f_write);
	}

	fclose(f_write);

	//读文件
	FILE * f_read = fopen("./test02.txt", "r");
	if (f_read == NULL)
	{
		return;
	}
	while ( !feof(f_read ))
	{
		char buf[1024] = { 0 };
		fgets(buf, 1024, f_read);
		printf("%s", buf);
	}

	fclose(f_read);
}

//按照块读写文件:fread(), fwirte()
struct Hero
{
	char name[64];
	int age;
};
void test03()
{
	//写文件  wb二进制方式
	FILE * f_write = fopen("./test03.txt", "wb");
	if (f_write == NULL)
	{
		return;
	}

	struct Hero heros[4] = 
	{
		{ "亚瑟" , 18 },
		{ "赵云", 28 },
		{ "妲己", 19 },
		{ "孙悟空", 99 },
	};

	for (int i = 0; i < 4;i++)
	{
		//参数1 数据地址  参数2  块大小   参数3  块个数   参数4  文件指针
		fwrite(&heros[i], sizeof(struct Hero), 1, f_write);
	}

	fclose(f_write);

	//读文件  
	FILE * f_read = fopen("./test03.txt", "rb");  // read binary
	if (f_read == NULL)
	{
		return;
	}

	struct Hero temp[4];
	//参数1 数据地址  参数2  块大小   参数3  块个数   参数4  文件指针
	fread(&temp, sizeof(struct Hero), 4, f_read);

	for (int i = 0; i < 4;i++)
	{
		printf("姓名:%s  年龄:%d \n", temp[i].name, temp[i].age);
	}
	fclose(f_read);
}

//按照格式化读写文件:fprintf(), fscanf()
void test04()
{
	//写文件
	FILE * f_write = fopen("./test04.txt", "w");
	if (f_write == NULL)
	{
		return;
	}

	fprintf(f_write, "hello world %d年 %d月 %d日", 2018, 7, 5);

	//关闭文件
	fclose(f_write);


	//读文件
	FILE * f_read = fopen("./test04.txt", "r");
	if (f_read == NULL)
	{
		return;
	}

	char buf[1024] = { 0 };
	while (!feof(f_read))
	{
		fscanf(f_read, "%s", buf);
		printf("%s\n", buf);
	}

	fclose(f_read);
}

//按照随机位置读写文件
void test05()
{
	FILE * f_write = fopen("./test05.txt", "wb");
	if (f_write == NULL)
	{
		return;
	}

	struct Hero heros[4] =
	{
		{ "亚瑟", 18 },
		{ "赵云", 28 },
		{ "妲己", 19 },
		{ "孙悟空", 99 },
	};

	for (int i = 0; i < 4; i++)
	{
		//参数1 数据地址  参数2  块大小   参数3  块个数   参数4  文件指针
		fwrite(&heros[i], sizeof(struct Hero), 1, f_write);
	}

	fclose(f_write);


	//读取妲己数据
	FILE * f_read = fopen("./test05.txt", "rb");
	if (f_read == NULL)
	{
		//error 宏 
		
		//printf("文件打开失败\n");
		perror("文件打开失败");
		return;
	}

	//创建临时结构体
	struct Hero temp;

	//改变文件光标位置
	fseek(f_read, sizeof(struct Hero) *2, SEEK_SET);

	fseek(f_read, -(long)sizeof(struct Hero) * 2, SEEK_END);

	rewind(f_read); //将文件光标置首

	fread(&temp, sizeof(struct Hero), 1, f_read);

	printf("姓名: %s 年龄: %d\n", temp.name, temp.age);

	fclose(f_read);

}


int main(){
	//test01();
	//test02();
	//test03();
	//test04();
	test05();

	system("pause");
	return EXIT_SUCCESS;
}
  • 05 文件读写注意事项.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>


//注意事项1
void test01()
{
	FILE * f_read = fopen("./test.txt", "r");
	if (f_read == NULL)
	{
		return;
	}

	char ch;

#if 0
	//aaaaaaaaaEOF
	//         |
	while ( !feof(f_read))
	{
		ch = fgetc(f_read);

		if (feof(f_read))
		{
			break;
		}

		printf("%c", ch);
	}
#endif 

	while ( ( ch = fgetc(f_read)) != EOF)
	{
		printf("%c", ch);
	}

	fclose(f_read);

}

//注意事项2 
struct Hero
{
	char * name; //如果属性开辟到堆区,不要存指针到文件中,要将指针指向的内容存放到文件中
	int age;
};


int main(){
	test01();
	//printf(" aaaaa\n");
	//printf("%caaaaa\n",EOF);
	system("pause");
	return EXIT_SUCCESS;
}
  • 06 配置文件读写案例
  • 头文件--config.h
 #define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//配置信息 结构体
struct ConfigInfo
{
	char key[64];
	char value[64];
};

//获取有效行数
int getFileLines(char * filePath);

//检测当前行是否是有效信息
int isValidLines(char *str);

//解析文件
void parseFile(char * filePath, int lines , struct  ConfigInfo ** configinfo);

//根据key获取对应value
char * getInfoByKey(char * key, struct ConfigInfo * configinfo, int len);

//释放内存
void freeConfigInfo(struct ConfigInfo * configinfo);
  • 源文件--config.c
#include "config.h"

int getFileLines(char * filePath)
{
	FILE * file = fopen(filePath, "r");
	if (file == NULL)
	{
		return -1;
	}

	char buf[1024] = { 0 };
	int lines = 0;
	while ( fgets(buf,1024,file) != NULL)
	{
		if (isValidLines(buf))
		{
			lines++;
		}
		memset(buf, 0, 1024);
	}

	return lines;

	fclose(file);
}

int isValidLines(char *str)
{
	if (strchr(str, ':') == NULL)
	{
		return 0; //返回假 代表无效行
	}

	return 1;
}

//解析文件
void parseFile(char * filePath, int lines, struct  ConfigInfo ** configinfo)
{
	struct ConfigInfo * info = malloc(sizeof(struct ConfigInfo) * lines);

	if (info == NULL)
	{
		return;
	}

	FILE * file = fopen(filePath, "r");
	if (file == NULL)
	{
		return;
	}
	char buf[1024] = { 0 };
	int index = 0;
	while ( fgets(buf,1024,file ) != NULL)
	{
		if (isValidLines(buf))
		{
			//有效信息 才去解析
			//清空 key和value数组
			//heroName:aaaa\n
			memset(info[index].key, 0, 64);
			memset(info[index].value, 0, 64);
			char * pos = strchr(buf, ':');
			strncpy(info[index].key, buf, pos - buf);
			strncpy(info[index].value, pos + 1, strlen(pos + 1)-1);
			index++;
		}
		memset(buf, 0, 1024);
	}
	*configinfo = info;
}

char * getInfoByKey(char * key, struct ConfigInfo * configinfo, int len)
{
	for (int i = 0; i < len;i++)
	{
		if (strcmp(key, configinfo[i].key) == 0)
		{
			return configinfo[i].value;
		}
	}

	return NULL;
}

//释放内存
void freeConfigInfo(struct ConfigInfo * configinfo)
{
	if (configinfo != NULL)
	{
		free(configinfo);
		configinfo = NULL;
	}
}
  • 源文件--06 配置文件读写案例.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include "config.h"


int main(){

	char * filePath = "./config.txt";
	int len = getFileLines(filePath);
	printf("文件的有效行数为:%d\n", len);

	struct ConfigInfo * configInfo = NULL;
	parseFile(filePath, len, &configInfo);

	//测试根据key获取value
	printf("heroId = %s\n", getInfoByKey("heroId", configInfo, len));
	printf("heroName = %s\n", getInfoByKey("heroName", configInfo, len));
	printf("heroAtk = %s\n", getInfoByKey("heroAtk", configInfo, len));
	printf("heroDef = %s\n", getInfoByKey("heroDef", configInfo, len));
	printf("heroInfo = %s\n", getInfoByKey("heroInfo", configInfo, len));

	//释放空间
	freeConfigInfo(configInfo);
	configInfo = NULL;


	system("pause");
	return EXIT_SUCCESS;
}

Day08

笔记

1	链表
	1.1	引出- 数组缺陷
		1.1.1	数组是一个静态空间,一旦分配内存,就不可以动态扩展,空间可能分配多或者分配的少,操作不精准
		1.1.2	对于头部的插入删除效率低
	1.2	链表
		1.2.1	由节点组成
		1.2.2	而节点由  数据域  和  指针域组成
			1.2.2.1	数据域是维护数据的
			1.2.2.2	指针域 维护下一个节点的位置
		1.2.3	链表可以解决数组的缺陷
		1.2.4	链表的分类
			1.2.4.1	静态链表、动态链表
			1.2.4.2	单向链表、双向链表、单向循环链表、双向循环链表
2	静态链表和动态链表
	2.1	静态链表分配在栈上
	2.2	动态链表分配到堆区
	2.3	实现链表的初始化以及遍历功能
3	链表基本使用
	3.1	带头节点链表和不带头节点链表
		3.1.1	带头好处:带着头节点的链表永远固定了头节点的位置
	3.2	初始化链表  init_LinkList
	3.3	遍历链表    foreach_LinkList
	3.4	插入链表    insert_LinkList  利用两个辅助指针 实现插入
	3.5	删除链表    delete_LinkList  利用两个辅助指针 实现删除
	3.6	清空链表    clear_LinkList   将所有有数据节点释放掉,可以在使用
	3.7	销毁链表    destroy_LinkList  将整个链表释放掉,不可以再使用
4	函数指针
	4.1	函数名本质就是一个函数指针
	4.2	可以利用函数指针 调用函数 
5	函数指针定义方式
	5.1		//1、先定义出函数类型,再通过类型定义函数指针
		5.1.1	typedef void(FUNC_TYPE)(int, char);
	5.2		//2、定义出函数指针类型,通过类型定义函数指针变量
		5.2.1	typedef void( * FUNC_TYPE2)(int, char);
	5.3		//3、直接定义函数指针变量
		5.3.1	void(*pFunc3)(int, char) = func;
	5.4	函数指针和指针函数
		5.4.1		//函数指针  指向了函数的指针
		5.4.2		//指针函数  函数返回值是指针的函数
	5.5	函数指针数组
		5.5.1		void(*pArray[3])();
6	函数指针做函数参数(回调函数)
	6.1	利用回调函数实现打印任意类型数据
	6.2	提供能够打印任意类型数组函数
	6.3	利用回调函数 提供查找功能
7	作业:超难
	7.1	提供一个函数,实现对任意类型的数组进行排序,排序规则利用选择排序,排序的顺序 用户可以自己指定
8

Code

  • 01 静态链表.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//节点的结构体
struct LinkNode
{
	int num; //数据域
	struct LinkNode * next; //指针域
};

void test01()
{
	//创建节点
	struct LinkNode node1 = { 10, NULL };
	struct LinkNode node2 = { 20, NULL };
	struct LinkNode node3 = { 30, NULL };
	struct LinkNode node4 = { 40, NULL };
	struct LinkNode node5 = { 50, NULL };

	//建立关系
	node1.next = &node2;
	node2.next = &node3;
	node3.next = &node4;
	node4.next = &node5;

	//遍历链表
	struct LinkNode * pCurrent = &node1;

	while (pCurrent != NULL)
	{
		printf("%d\n", pCurrent->num);
		pCurrent = pCurrent->next;
	}


}

int main(){
	test01();


	system("pause");
	return EXIT_SUCCESS;
}
  • 02 动态链表.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

struct LinkNode
{
	int num;
	struct LinkNode * next;
};

void test01()
{
	//创建节点
	struct LinkNode * node1 = malloc(sizeof(struct LinkNode));
	struct LinkNode * node2 = malloc(sizeof(struct LinkNode));
	struct LinkNode * node3 = malloc(sizeof(struct LinkNode));
	struct LinkNode * node4 = malloc(sizeof(struct LinkNode));
	struct LinkNode * node5 = malloc(sizeof(struct LinkNode));

	//给数据域赋值
	node1->num = 100;
	node2->num = 200;
	node3->num = 300;
	node4->num = 400;
	node5->num = 500;

	//建立关系
	node1->next = node2;
	node2->next = node3;
	node3->next = node4;
	node4->next = node5;
	node5->next = NULL;

	//遍历链表
	struct LinkNode * pCurrent = node1;
	while (pCurrent!=NULL)
	{
		printf("%d\n", pCurrent->num);
		pCurrent = pCurrent->next;
	}

	free(node1);
	free(node2);
	free(node3);
	free(node4);
	free(node5);
	node1 = NULL;
	node2 = NULL;
	node3 = NULL;
	node4 = NULL;
	node5 = NULL;
}

int main(){

	test01();

	system("pause");
	return EXIT_SUCCESS;
}

03 链表的基本操作

  • 头文件--linkList.h
#pragma  once
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

struct LinkNode
{
	int num;
	struct LinkNode * next;
};

//初始化链表
struct LinkNode * initLinkList();

//遍历链表
void foreach_LinkList(struct LinkNode * pHeader);

//插入链表
void insert_LinkList(struct LinkNode * pHeader, int oldVal, int newVal);

//删除链表
void delete_LinkList(struct LinkNode * pHeader, int val);

//清空链表
void clear_LinkList(struct LinkNode * pHeader);

//销毁链表
void destroy_LinkList(struct LinkNode * pHeader);
  • 源文件--lintList.c
#include "linkList.h"


//初始化链表
struct LinkNode * initLinkList()
{
	//创建头节点
	struct LinkNode * pHeader = malloc(sizeof(struct LinkNode));

	if (pHeader == NULL)
	{
		return NULL;
	}

	//初始化头节点
	//pHeader->num = -1;  //头节点 不维护数据域
	pHeader->next = NULL;

	//记录尾节点位置,方便插入新的数据
	struct LinkNode * pTail = pHeader;
	int val = -1;
	while (1)
	{
		//让用户初始化几个节点,如果用户输入的是-1,代表插入结束
		printf("请初始化链表,如果输入-1代表结束\n");
		scanf("%d", &val);

		if (val == -1)
		{
			break;
		}

		//如果输入不是-1  插入节点到链表中
		 struct LinkNode * newNode = malloc(sizeof(struct LinkNode));
		 newNode->num = val;
		 newNode->next = NULL;

		 //更改指针的指向
		 pTail->next = newNode;
		 //更新新的尾节点的指向
		 pTail = newNode;

	}


	return pHeader;
}

//遍历链表
void foreach_LinkList(struct LinkNode * pHeader)
{
	if (pHeader == NULL)
	{
		return;
	}

	struct LinkNode * pCurrent = pHeader->next; //指定第一个有真实数据的节点

	while (pCurrent!=NULL)
	{
		printf("%d\n", pCurrent->num);
		pCurrent = pCurrent->next;
	}

}

//插入链表
void insert_LinkList(struct LinkNode * pHeader, int oldVal, int newVal)
{
	if (pHeader == NULL)
	{
		return;
	}

	//创建两个临时的节点
	struct LinkNode * pPrve = pHeader;
	struct LinkNode * pCurrent = pHeader->next;

	while (pCurrent != NULL)
	{
		if (pCurrent->num == oldVal)
		{
			break;
		}
		//如果没找到对应的位置,辅助指针向后移动
		pPrve = pCurrent;
		pCurrent = pCurrent->next;
	}

	//创建新节点
	struct LinkNode * newNode = malloc(sizeof(struct LinkNode));
	newNode->num = newVal;
	newNode->next = NULL;


	//建立关系
	newNode->next = pCurrent;
	pPrve->next = newNode;


}


//删除链表
void delete_LinkList(struct LinkNode * pHeader, int val)
{
	if (pHeader==NULL)
	{
		return;
	}

	//创建两个辅助指针变量
	struct LinkNode * pPrev = pHeader;
	struct LinkNode * pCurrent = pHeader->next;

	while (pCurrent != NULL)
	{
		if (pCurrent->num == val)
		{
			break;
		}
		//没有找到数据,辅助指针向后移动
		pPrev = pCurrent;
		pCurrent = pCurrent->next;
	}

	if (pCurrent == NULL) //没有找到用户要删除的数据
	{
		return;
	}

	//更改指针的指向进行删除
	pPrev->next = pCurrent->next;

	//删除掉待删除的节点
	free(pCurrent);
	pCurrent = NULL;

}


//清空链表
void clear_LinkList(struct LinkNode * pHeader)
{
	if (pHeader == NULL)
	{
		return;
	}

	struct LinkNode * pCurrent = pHeader->next;

	while (pCurrent != NULL)
	{
		//先保存住下一个节点的位置
		struct LinkNode * nextNode = pCurrent->next;

		free(pCurrent);

		pCurrent = nextNode;
	}

	pHeader->next = NULL;

}

//销毁链表
void destroy_LinkList(struct LinkNode * pHeader)
{

	if (pHeader == NULL)
	{
		return;
	}

	//先清空链表
	clear_LinkList(pHeader);

	//再释放头节点

	free(pHeader);
	pHeader = NULL;

}
  • 源文件--03 链表的基本操作.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include "linkList.h"

void test01()
{
	//初始化链表
	struct LinkNode * pHeader = initLinkList();

	//遍历链表
	printf("遍历链表结果为:\n");
	foreach_LinkList(pHeader);

	//插入链表
	// 10 1000  2000 20 3000 30  500
	insert_LinkList(pHeader, 20, 1000);
	insert_LinkList(pHeader, 20, 2000);
	insert_LinkList(pHeader, -1, 500);
	insert_LinkList(pHeader, 30, 3000);
	printf("插入链表后,遍历链表结果为:\n");
	foreach_LinkList(pHeader);


	//删除链表
	// 10  20  30  500
	delete_LinkList(pHeader, 2000);
	delete_LinkList(pHeader, 3000);
	delete_LinkList(pHeader, 1000);
	delete_LinkList(pHeader, -1);
	printf("删除链表后,遍历链表结果为:\n");
	foreach_LinkList(pHeader);

	//清空链表
	clear_LinkList(pHeader);
	printf("清空链表后,遍历链表结果为:\n");
	insert_LinkList(pHeader, 111, 111);
	insert_LinkList(pHeader, 222, 222);
	insert_LinkList(pHeader, 333, 333);
	foreach_LinkList(pHeader);

	//销毁链表
	destroy_LinkList(pHeader);
	pHeader = NULL;
		
}

int main(){

	test01();

	//printf("%d\n", test01);

	system("pause");
	return EXIT_SUCCESS;
}
  • 04 函数指针的定义方式
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

void func(int a ,char c)
{
	printf("hello world\n");
}

void test01()
{
	//1、先定义出函数类型,再通过类型定义函数指针
	typedef void(FUNC_TYPE)(int, char);

	FUNC_TYPE * pFunc = func;
	//pFunc(10, 'a');

	//2、定义出函数指针类型,通过类型定义函数指针变量
	typedef void( * FUNC_TYPE2)(int, char);

	FUNC_TYPE2 pFunc2 = func;
	//pFunc2(20, 'b');


	//3、直接定义函数指针变量
	void(*pFunc3)(int, char) = func;
	pFunc3(30, 'c');

	//函数指针 和 指针函数 区别?
	//函数指针  指向了函数的指针
	//指针函数  函数返回值是指针的函数
}


//函数指针的数组
void func1()
{
	printf("func1 调用了\n");
}

void func2()
{
	printf("func2 调用了\n");
}

void func3()
{
	printf("func3 调用了\n");
}

void test02()
{
	void(*pArray[3])(); 

	pArray[0] = func1;
	pArray[1] = func2;
	pArray[2] = func3;

	for (int i = 0; i < 3;i++)
	{
		pArray[i]();
	}
}

int main(){
	//test01();
	test02();

	system("pause");
	return EXIT_SUCCESS;
}
  • 05 函数指针做函数参数.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//提供一个打印函数,可以打印任意类型的数据
void printText( void * data , void(*myPrint)(void *) )
{
	myPrint(data);

}



void myPrintInt(void * data)
{
	int * num = data;
	printf("%d\n", *num);
}

void test01()
{
	int a = 10;
	printText(&a, myPrintInt);
}


struct Person
{
	char name[64];
	int age;
};

void myPrintPerson(void * data)
{
	struct Person * p = data;
	printf("姓名: %s 年龄: %d\n", p->name, p->age);
}

void test02()
{
	struct Person p = { "Tom", 18 };

	printText(&p, myPrintPerson);

}

int main(){

	//test01();
	test02();
	system("pause");
	return EXIT_SUCCESS;
}
  • 06 回调函数案例.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//提供一个函数,实现可以打印任意类型的数组 

void printAllArray(void * pArray , int eleSize, int len , void(*myPrint)(void*) )
{
	char * p = pArray;

	for (int i = 0; i < len;i++)
	{
		//获取数组中每个元素的首地址
		char * eleAddr = p + eleSize * i;
		//printf("%d\n", *(int *)eleAddr);
		//交还给用户做打印操作
		myPrint(eleAddr);
	}

}

void myPrintInt(void * data)
{
	int * num = data;
	printf("%d\n", *num);
}

void test01()
{
	int arr[5] = { 1, 2, 3, 4, 5 };
	int len = sizeof(arr) / sizeof(int);
	printAllArray(arr, sizeof(int), len, myPrintInt);
}

struct Person
{
	char name[64];
	int age;
};

void myPrintperson(void * data)
{
	struct Person * p = data;
	printf("姓名:%s  年龄:%d \n", p->name, p->age);
}


//查找数组中的元素是否存在
//参数1  数组首地址   参数2  每个元素的大小  参数3  数组元素个数  参数4 查找数据
int findArrayEle(void * pArray, int eleSize, int len, void * data ,  int(*myCompare)(void* ,void* )  )
{
	char * p = pArray;

	for (int i = 0; i < len;i++)
	{
		//每个元素的首地址
		char * eleAddr = p + eleSize * i;

		//if ( 数组中的变量的元素 == 用户传入的元素)
		if ( myCompare(eleAddr,data)  )
		{
			return 1;
		}
	}

	return 0;

}

int myComparePerson(void * data1,void * data2)
{
	struct Person * p1 = data1;
	struct Person * p2 = data2;

	//if ( strcmp( p1->name , p2->name) == 0  &&  p1->age == p2->age)
	//{
	//	return 1;
	//}
	//return  0;

	return   strcmp(p1->name, p2->name) == 0 && p1->age == p2->age;

}

void test02()
{
	struct Person personArray[] =
	{
		{ "aaa", 10 },
		{ "bbb", 20 },
		{ "ccc", 30 },
		{ "ddd", 40 },
	};
	int len = sizeof(personArray) / sizeof(struct Person);
	printAllArray(personArray, sizeof(struct Person), len, myPrintperson);

	//查找数组中指定的元素是否存在
	struct Person p = { "ccc", 30 };

	int ret = findArrayEle(personArray, sizeof(struct Person), len, &p, myComparePerson);

	if (ret)
	{
		printf("找到了元素\n");
	}
	else
	{
		printf("未找到\n");
	}
}

int main(){

	//test01();
	test02();
	system("pause");
	return EXIT_SUCCESS;
}

Day07

笔记 Day07笔记(动态库--> __declspec(dllexport)int mySub(int a, int b)😉

1	链表反转作业
	1.1	利用3个辅助指针,实现链表反转
	1.2	提供返回链表节点个数 函数
2	回调函数作业-实现对任意数据类型数组进行排序
	2.1	利用选择排序实现大框架
	2.2	对比功能交还给用户指定
	2.3	利用回调函数技术来实现对比
3	预处理指令
	3.1	头文件  #include 
		3.1.1	<>  “”区别
		3.1.2	<> 包含系统头
		3.1.3	“” 包含自定义头
	3.2	宏
		3.2.1	宏常量
			3.2.1.1	不重视作用域
			3.2.1.2	没有数据类型
			3.2.1.3	利用 #undef 卸载宏
		3.2.2	宏函数
			3.2.2.1	将频繁、短小函数写成宏函数
			3.2.2.2	优点:以空间换时间
	3.3	条件编译
		3.3.1	#ifdef   #else   #endif  测试存在
		3.3.2	#ifndef  #else   #endif   测试不存在
		3.3.3	#if    #else   #endif    自定义条件编译
	3.4	特殊宏
		3.4.1	__FILE__  宏所在文件路径
		3.4.2	__LINE__  宏所在行
		3.4.3	__DATE__ 宏编译日期   
		3.4.4	__TIME__ 宏编译时间
4	静态库配置
	4.1	右键项目->属性 ->常规->配置类型 ->静态库
	4.2	生成项目   生成.lib文件
	4.3	将.lib和 .h交给用户
	4.4	测试
5	动态库配置
	5.1	右键项目->属性 ->常规->配置类型 ->动态库 .dll
	5.2	生成项目  生成 .lib  .dll
	5.3	静态库中生成的.lib和动态库生成的.lib是不同的,动态库中的.lib只会放变量的声明和 导出函数的声明,函数实现体放在.dll中
	5.4	导出函数/外部函数 : __declspec(dllexport)int mySub(int a, int b);
	5.5	测试
		5.5.1	#pragma  comment( lib,"./mydll.lib")
6	递归函数
	6.1	本质:函数自身调用自身
	6.2	注意事项:递归函数必须有结束条件,函数有出口
7	面向接口封装案例
	7.1	甲乙两方设计接口
	7.2	甲方实现代码
	7.3	乙方实现代码
	7.4	接口对接
8	

Code

  • 01 回调函数作业-实现对任意类型数组排序.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

void selectSort( void * pAddr , int elesize , int len , int(*myCompare)(void * ,void *) )
{
	char * temp = malloc(elesize);

	for (int i = 0; i < len;i++)
	{
		int minOrMax = i; //定义最小值 或者 最大值 下标
		for (int j = i + 1; j < len;j++)
		{
			//定义出 j元素地址
			char * pJ = (char*)pAddr + elesize * j;
			char * pMinOrMax = (char*)pAddr + elesize * minOrMax;
			//if ( pAddr[j] < pAddr[minOrMax])

			/* 从大到小
			if ( *num1 > *num2)
			{
			return 1;
			}
			return 0;
			*/

			if (  myCompare(pJ,pMinOrMax ))
			{
				minOrMax = j; //更新最小值或者最大值下标
			}
		}

		if ( i != minOrMax)
		{
			//交换i和minOrMax 下标元素
			char * pI = (char*)pAddr + i*elesize;

			char * pMinOrMax = (char*)pAddr + minOrMax * elesize;

			memcpy(temp, pI, elesize);
			memcpy(pI, pMinOrMax, elesize);
			memcpy(pMinOrMax, temp, elesize);

		}

	}

	if (temp != NULL)
	{
		free(temp);
		temp = NULL;
	}

}

int myCompareInt(void * data1, void * data2)
{
	int * num1 = data1;
	int * num2 = data2;

	if ( *num1 > *num2)
	{
		return 1;
	}
	return 0;
}

void test01()
{
	int arr[] = { 10, 30, 20, 60, 50, 40 };

	int len = sizeof(arr) / sizeof(int);
	selectSort(arr, sizeof(int), len, myCompareInt);

	for (int i = 0; i < len;i++)
	{
		printf("%d\n", arr[i]);
	}

}


struct Person
{
	char name[64];
	int age;
};

int myComparePerson(void * data1, void * data2)
{
	struct Person * p1 = data1;
	struct Person * p2 = data2;

	//if ( p1->age < p2->age)
	//{
	//	return  1;
	//}
	//return 0;
	//按照年龄 升序排序
	return  p1->age < p2->age;

}

void test02()
{
	struct Person pArray[] =
	{
		{ "aaa", 10 },
		{ "bbb", 40 },
		{ "ccc", 20 },
		{ "ddd", 30 },
	};
	int len = sizeof(pArray) / sizeof(struct Person);
	selectSort(pArray, sizeof(struct Person), len, myComparePerson);

	for (int i = 0; i < len;i++)
	{
		printf("姓名:%s 年龄:%d\n", pArray[i].name, pArray[i].age);
	}

}


int main(){
	//test01();
	test02();

	system("pause");
	return EXIT_SUCCESS;
}
  • 02 预处理指令.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//1 、头文件包含  "" <>区别
// ""包含自定义头文件
// <> 包含系统头文件

//2、 宏 常量  
//  不重视作用域
//  可以利用 undef卸载宏
//  宏常量 没有数据类型的

//宏 函数
//  将短小、频繁使用的函数写成宏函数
//  加括号保证运算完整性
//  优点:以空间换时间

void test01()
{
	#define  MAX 1024
	//#undef  MAX
}

//3、 条件编译
//#define  DEBUG
#ifdef DEBUG
void func()
{
	printf("Debug版本发布\n");
}
#else 
	//自定义条件编译
#if 0
void func()
{
	printf("Release1版本发布\n");
}
#else 
void func()
{
	printf("Release2版本发布\n");
}
#endif


#endif



//特殊宏
void doWork(char * p)
{
	if (p == NULL)
	{
		printf("文件: %s 第 %d 行 出错了\n", __FILE__, __LINE__);
		printf("日期:%s\n", __DATE__);
		printf("时间:%s\n", __TIME__);
		return;
	}


}
void test02()
{
	doWork(NULL);
	
}


int main(){

	//printf("MAX = %d\n", MAX);
	//func();
	test02();


	system("pause");
	return EXIT_SUCCESS;
}

03 静态库测试

  • 头文件 -- mylib.h
#pragma  once 

//实现一个加法 ,返回两个数相加的结果
int myAdd(int a, int b);
  • 源文件 --03 静态库测试.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

int main(){

	printf("%d\n", myAdd(10, 20));


	system("pause");
	return EXIT_SUCCESS;
}
  • 04 动态库测试.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

#pragma  comment( lib,"./mydll.lib")

int main(){

	printf("10 - 20 = %d\n", mySub(10, 20));


	system("pause");
	return EXIT_SUCCESS;
}
  • 05 递归函数.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//利用递归实现字符串逆序遍历
void reversePrint(char * p)
{
	if (*p =='\0')
	{
		return;
	}

	reversePrint(p + 1);

	printf("%c\n", *p);

}

void test01()
{
	char * str = "abcdefg";
	reversePrint(str);
}


int fibonacci(int pos)
{
	if (pos == 1 ||  pos ==2)
	{
		return 1;
	}

	return fibonacci(pos - 1) + fibonacci(pos - 2);
}

void test02()
{
	//斐波那契数列
	// 1 1 2 3 5 8 13 21  34  55...
	printf("第9为数字为:%d\n", fibonacci(9));
	printf("第10为数字为:%d\n", fibonacci(10));
	printf("第20为数字为:%d\n", fibonacci(20));

}


int main(){

	//test01();
	test02();
	system("pause");
	return EXIT_SUCCESS;
}

06 面向接口封装案例

  • 头文件--
#pragma  once
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

struct Player
{
	char name[64]; //玩家姓名
	int level; //玩家等级
	int  exp; //玩家经验
};

//初始化游戏  参数1  玩家指针   参数2  玩家姓名
void INIT_GAME_COMPANY1(void ** player, char * name);

//副本战斗  返回战斗是否胜利 1、代表胜利  0、代表失败   参数1  玩家  参数2 游戏副本难度
int FIGHT_GAME_COMPANY1(void * player, int gameDiff);

//查看玩家信息
void PRINT_GAME_COMPANY1(void * player);

//离开游戏
void EXIT_GAME_COMPANY1(void * player);

//判断游戏是否胜利
int isWin(int winRate, int diff);
  • 源文件 -- gameCompany1.c
#include "gameCompany1.h"

//初始化游戏  参数1  玩家指针   参数2  玩家姓名
void INIT_GAME_COMPANY1(void ** player, char * name)
{
	struct Player * player1 = malloc(sizeof(struct Player));

	if (player1 == NULL)
	{
		printf("初始化失败\n");
		return;
	}

	*player = player1;

	strcpy(player1->name, name);
	player1->level = 0;
	player1->exp = 0;

}

//副本战斗  返回战斗是否胜利 1、代表胜利  0、代表失败   参数1  玩家  参数2 游戏副本难度
int FIGHT_GAME_COMPANY1(void * p, int gameDiff)
{
	struct Player * player = p;

	int addExp = 0;  //增加经验值

	switch (gameDiff)
	{
	case 1:
		addExp = isWin(90, 1);
		break;
	case 2:
		addExp = isWin(50, 2);
		break;
	case 3:
		addExp = isWin(30, 3);
		break;
	default:
		break;
	}

	//累积经验到玩家身上
	player->exp += addExp;
	player->level = player->exp / 10;

	if (addExp == 0)
	{
		return 0;
	}
	else
	{
		return 1;
	}


}

//判断游戏是否胜利
int isWin(int winRate, int diff)
{
	int random = rand() % 100 + 1;  // 1 ~ 100
	if (random <= winRate)
	{
		return diff * 10;
	}
	else 
	{
		return 0;
	}
}


//查看玩家信息
void PRINT_GAME_COMPANY1(void * p)
{
	struct Player * player = p;
	printf("玩家<%s> ------ 当前等级:<%d>级 ----- 当前经验: <%d> \n", player->name, player->level, player->exp);
}

//离开游戏
void EXIT_GAME_COMPANY1(void * player)
{
	if ( player==NULL)
	{
		return;
	}

	free(player);
	player = NULL;
}
  • 06 面向接口封装案例.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include "gameCompany1.h"
#include <time.h>

//初始化游戏  参数1  玩家指针   参数2  玩家姓名
typedef void(*INIT_GAME)(void ** player , char * name);

//副本战斗  返回战斗是否胜利 1、代表胜利  0、代表失败   参数1  玩家  参数2 游戏副本难度
typedef int(*FIGHT_GAME)(void * player, int gameDiff);

//查看玩家信息
typedef void(*PRINT_GAME)(void * player);

//离开游戏
typedef void(*EXIT_GAME)(void * player);


void playGame(INIT_GAME init, FIGHT_GAME fight, PRINT_GAME printGame, EXIT_GAME exitGame)
{
	//初始化游戏
	void * player = NULL;
	printf("请输入姓名:\n");
	char userName[64];
	scanf("%s", userName);

	init(&player, userName);

	//副本难度 变量
	int diff = -1;

	while (1)
	{
		getchar();
		system("cls");
		printf("请选择游戏难度:\n");
		printf("1、简单\n");
		printf("2、中等\n");
		printf("3、困难\n");

		scanf("%d", &diff);

		getchar(); //取走换行符

		//战斗
		int ret = fight(player, diff);
		if (ret == 0)
		{

			printf("游戏失败\n");
			break;
		}
		else
		{
			printf("挑战成功,玩家当前信息如下:\n");

			printGame(player);
		}

	}

	
	//关闭游戏
	exitGame(player);
}

int main(){

	srand((unsigned int)time(NULL));

	playGame(INIT_GAME_COMPANY1, FIGHT_GAME_COMPANY1, PRINT_GAME_COMPANY1, EXIT_GAME_COMPANY1);

	system("pause");
	return EXIT_SUCCESS;
}

mydll

  • 头文件--mydll.h
#pragma  once

//实现两个数相减 函数  
//内部函数 
//int mySub(int a, int b);



//外部函数  导出函数
//生成 .lib  和 .dll
// 静态库中生成的.lib和动态库生成的.lib是不同的,动态库中的.lib只会放变量的声明和 导出函数的声明,函数实现体放在.dll中
__declspec(dllexport)int mySub(int a, int b);
  • 源文件--mydll
#include "mydll.h"


int mySub(int a, int b)
{
	return a - b;
}

mylib

  • 头文件--mylib.h
#pragma  once 

//实现一个加法 ,返回两个数相加的结果
int myAdd(int a, int b);
  • mylib.c
#include "mylib.h"

int myAdd(int a, int b)
{
	return a + b;
}
posted @ 2021-07-11 19:57  zranguai  阅读(119)  评论(0)    收藏  举报