并非从0开始的c++ day9


后续部分课程涉及数据结构,这里直接跳过

配置文件读写练习

需求

需求:从根目录config文件中读取数据,建立一个结构体含有key和value两个属性,可以通过config中响应的key访问对应的value,且可以跳过不需要的字符

判断文件有效行数

//获取文件有效行数
int getFileLine(const char* filePath)
{
	FILE* file = fopen(filePath, "r");

	if (file == NULL)
	{
		return -1;
	}

	char buf[1024] = { 0 };
	int line = 0;

	while (fgets(buf, 1024, file) != NULL)
	{
		//检测是否有效
		if (isInvalidLine(buf))
		{
			line++;
		}

	}

	return line;
}

根据字符串判断是否是有效行

//判断传入的字符串是否为有效行 是返回1 否0
int isInvalidLine(char* str)
{
	if (str[0] == '\n' || strchr(str, ':') == NULL)
	{
		return 0;
	}
	return 1;
}

strchr可以用来查找字符串是否含有传入的字符

文件解析


//文件解析
void parseFile(const char* filePath, int lines, struct ConfigInfo** configInfo)
{
	struct ConfigInfo* config = malloc(sizeof(struct ConfigInfo) * lines);
	if (config == NULL)
	{
		return;
	}

	FILE* file = fopen(filePath, "r");
	if (file == NULL)
	{
		return;
	}


	char buf[1024] = { 0 };//将读取的每行数据放入到buf中
	int index = 0;
	while (fgets(buf,1024,file)!= NULL)
	{
		if (isInvalidLine(buf))
		{
			//heroId : 1
			//清空key和value值
			memset(config[index].key, 0, 64);
			memset(config[index].value, 0, 64);

			char* pos = strchr(buf, ':');
			//截取key数据
			strncpy(config[index].key, buf, pos -buf);
			//截取value数据
			strncpy(config[index].value, pos+1,strlen(pos+1)-1);//-1是不用文件中的换行符
			printf("key = %s\n value = %s \n", config[index].key, config[index].value);

			index++;
		}
		memset(buf, 0, 1024);
	}

	*configInfo = config;
}

strncpy用于截取数据,可以在参数一的位置,将参数二到参数三之间的数据截取出来
不过我解析出来的文件里,汉字是乱码,还没搞清楚是为啥

根据key获取value的值

//根据key获取对应value
char* getValueByKey(char* key, struct ConfigInfo* configInfo, int lines)
{
	for (int i = 0; i < lines; i++)
	{
		if (strcmp(configInfo[i].key ,key)== 0)
		{
			return configInfo[i].value;
		}
	}
	return NULL;
}

释放内存

//释放内存
void freeSpace(struct ConfigInfo* configInfo)
{
	if (configInfo == NULL)
	{
		return;
	}
	free(configInfo);
	configInfo == NULL;
}

文件加密

需求:
加密:

  1. 数据左移4位
  2. 用或运算使所有数变成负数
  3. 加上(0000~1111)之间的随机数

解密:

  1. 左移1位
  2. 右移5位

feof是C语言标准库函数,其原型在stdio.h中,其功能是检测流上的文件结束符,如果文件结束,则返回非0值,否则返回0

加密

void codeFile(const char* sourceFile, const char* destFile)
{
	//# 35
	//short 0000 0000 0010 0011
	// << 4 0000 0010 0011 0000
	//  |   1000 0010 0011 0000
	//随机数 1000 0010 0011 ???? 0~15
	FILE* fp1 = fopen(sourceFile, "r");
	FILE* fp2 = fopen(destFile, "w");

	if (fp1 == NULL || fp2 == NULL)
		return;
	char ch;
	
	while ((ch = fgetc(fp1)) != EOF)
	{
		//给每个字符进行加密
		short temp = (short)ch;
	
		//左移4位
		temp = temp << 4;


		//编程负数
		temp = temp | 0x8000;

		//添加随机数
		temp = temp + rand() % 16;
		
		//将加密字符放入目标文件
		fprintf(fp2,"%hd\n",temp);
	}
	fclose(fp1);
	fclose(fp2);
}

在加密时,虽然有在代码中加入随机数,但是加密出来的结果依然每次都一样
这时需要给随机数一个随机数种子,我这里使用的是以时间作为基准的

#include <time.h>

	//随机数种子
	srand((unsigned int)time(NULL));
	

%hd 代表输出一个短整数,对应上面的short数据类型

解密

void decodeFile(char* sourceFile, char* destFile)
{
	//<<1  000 0010 0011 ????0
	//>>5  0000 0000 0010 0011
	FILE* fp1 = fopen(sourceFile, "r");
	FILE* fp2 = fopen(destFile, "w");

	if (fp1 == NULL || fp2 == NULL)
		return;
	short temp;

	while (!feof(fp1))
	{
		fscanf(fp1, "%hd", &temp);

		//temp = temp << 1
		temp <<= 2;
		temp >>= 5;

		char ch = (char)temp;
		fputc(ch, fp2);
	}
	fclose(fp1);
	fclose(fp2);
}

fscanf从输入流中读入数据,存储到对应的argument中,遇到空格和换行时结束,这里的temp需要是他的指针

函数指针

函数指针基本介绍

  • 函数指针 指向函数入口地址的指针
  • 函数名 函数的入口地址

函数指针写法:返回值类型 +(指针变量名)(形参列表)

func();
qDebug("%d",func);

//函数指针 指向函数地址
int * p = (int *)-775679270;
void (*pFunc)() = (void (*)())p;

pFunc();

函数指针的定义方式

一 、先定义出函数的类型,在通过类型定义函数指针变量

void test01()
{
	//先定义出函数的类型,在通过类型定义函数指针变量
	typedef void (FUNC_TYPE)(int, char);//定义出一个函数类型,返回值是void,形参列表(int,char);

	FUNC_TYPE* pFunc = func;

	pFunc(10, 'a');
}

二、先定义出函数指针的类型,再通过类型定义函数指针变量

void test02()
{
	//先定义出函数指针的类型,再通过类型定义函数指针变量
	
	typedef void (*FUNC_TYPE)(int, char);

	FUNC_TYPE pFunc = func;
	pFunc(20, 'c');
}

三、直接定义函数指针变量(最重要的)

void test03()
{
	//直接定义函数指针变量
	void(* p)(int,char) = func;
	p(30, 'd');
}

四、函数指针数组的定义方式

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

void test04()
{
	//函数指针数组的定义方式
	void (*func_array[3])();

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

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

函数指针做函数参数 —回调函数

回调函数案例1 打印任意类型数据

提供函数 可以打印任意类型数据

参数一 数据地址 参数二 函数指针

//提供一个函数,可以打印任意类型数据
void myPrint(void * data,void(*mp)(void *))
{
	//int* num = data;
	//printf("%d\n", num);

	mp(data);

}

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

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

void printDouble(void* data)
{
	double* num = data;
	printf("%f\n", *num);
}

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

void test01()
{
	int a = 10;
	myPrint(&a,printInt);

	double b = 3.14;;
	myPrint(&b,printDouble);

	struct Person p1 = { "aaa",18 };
	myPrint(&p1, printPerson);
}

回调函数案例2 打印任意类型数组


//参数1 传入数组首地址  参数2 数组中每个元素占用内存  参数3 数组长度
void printAllArray(void * arr,int eleSize,int len,void(*myPrint)(void *))
{
	char* p = arr;//利用p指针接收数组首地址
	for (int i = 0; i < len; i++)
	{
		//获取每个元素的首地址
		char* pAddr = p + eleSize * i;

		//printf("%d\n", *(int*)pAddr);
		myPrint(pAddr);
	}
}

回调函数案例3 查找数组中的元素

查找数组中指定元素是否存在,如果存在返回1,否则返回0,
利用回调函数 做元素的对比

int findArrayEle(void * array,int eleSize,int len,void *data,int (*myCompare)(void*,void *))
{
	char* p = array;
	for (int i = 0; i < len; i++)
	{
		//获取到每个元素的首地址
		char* eleAddr = p + eleSize*i;

		//if(用户传入的数据 == 数组中遍历的元素)
		//if (data == eleAddr)错误的,不可以直接用地址做比较
		if(myCompare(data,eleAddr))
		{
			return 1;
		}
	}
	return 0;
}

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

	//如果姓名相等 并且年龄相等 返回真,否则返回假
	if (strcmp(p1->name,p2->name) && p1->age == p2->age)
	{
		return 1;
	}
	else
		return 0;
}

void test03()
{
	//查找数组中是否有指定类型的元素,如果有返回1,如果没有返回0

	struct Person personArray[] =
	{
		{"aaa",18},
		{"bb",19},
		{"cccc",20},
		{"dddddd",21},
	};

	int len = sizeof(personArray) / sizeof(struct Person);

	struct Person p = { "ccc",20 };

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

	if (ret)
	{
		printf("找到了元素\n");
	}
	else {
		printf("未找到元素\n");
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值