Day21.C提高5

Day21.C提高5

一、结构体嵌套二级指针

/*当创建结构体变量后,如果其中的成员为指针类型的话,就要将此变量开辟至堆空间,是因为在创建结构体后,程序在运行结束之后,对于结构体变量所占的内存空间就已经分配好了,分配的大小为4字节(也就是一个指针的)大小,如果不重新在堆空间中开辟内存的话,就会导致溢出,因此,一般情况下,看到使用指针类型的数据的时候,应该在堆空间中存储。*/


#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

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

void test101()
{
	struct Teacher** t1 = malloc(sizeof(struct Teacher*) * 3);
	//开辟空间并进行赋值操作
	for (int i = 0; i < 3; i++)
	{
		t1[i] = malloc(sizeof(struct Teacher));
		t1[i]->name = malloc(sizeof(char) * 64);//给每个教师的名字开辟堆空间
		sprintf(t1[i]->name, "teacher_%d", i + 1);
		t1[i]->student = malloc(sizeof(char*) * 5);//每个老师可以带5个学生
		for (int j = 0; j < 5; j++)
		{
			t1[i]->student[j] = malloc(sizeof(char) * 64);
			sprintf(t1[i]->student[j], "teacher_%d_Stu_%d", i + 1, j + 1);
		}
	}
	//打印输出结果
	for (int i = 0; i < 3; i++)
	{
		printf("teacher_name : %s\n", t1[i]->name);
		for (int j = 0; j < 5; j++)
		{
			printf("\t%s_Stu_%d\n", t1[i]->name,j+1);
		}
		printf("\n");
	}
	//释放空间
	for (int i = 0; i < 3; i++)
	{
		if (NULL != t1[i]->name)
		{
			free(t1[i]->name);
			t1[i]->name = NULL;
		}
		for (int j = 0; j < 5; j++)
		{
			if (t1[i]->student[j] != NULL)
			{
				free(t1[i]->student[j]);
				t1[i]->student[j] = NULL;
			}
		}
		if (NULL != t1[i])
		{
			free(t1[i]);
			t1[i] = NULL;
		}
	}

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

int main()
{
	test101();
	return 0;
}

二、结构体偏移量

//通过地址加减偏移量,来打印相应的值
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<stddef.h>

struct A 
{
	char a1;
	int a2;

};

void test201()
{
	struct A a = { "b",20 };
	//C 库宏 offsetof(type, member-designator) 会生成一个类型为 size_t 的整型常量,它是一个结构成员相对于结构开头的字节偏移量。
	printf("A.a2:%d\n", *(int*)((char*)&a + offsetof(struct A, a2)));
	printf("A.a2:%d\n", *((int*)&a + 1));
}

struct C
{
	int a;
	double b;
};

struct B
{
	char a;
	double b;
	struct C c;
};

void test202()
{
	struct B b = { 'a',20,30,3.14 };
	int off1 = offsetof(struct B, c);
	int off2 = offsetof(struct C, b);

	printf("b.c.b:%f\n", *(double*)(((char*)&b + off1) + off2));	
}

int main(void)
{
	//test201();
	test202();


	system("pause");
	return EXIT_SUCCESS;
}

三、结构体内存字节对齐

	在用sizeof运算符求算某结构体所占空间时,并不是简单地将结构体中
所有元素各自占的空间相加,这里涉及到内存字节对齐的问题。

	从理论上讲,对于任何变量的访问都可以从任何地址开始访问,但是
事实上不是如此,实际上访问特定类型的变量只能在特定的地址访问,这
就需要各个变量在空间上按一定的规则排列, 而不是简单地顺序排列,这
就是内存对齐。

	举一个很简单的例子,例如我们在内存中存储数字,假如是按照我们预期
的顺序存储的方式进行存储,存储一个char 和一个int型的数据,假设计算机
在读取的时候是4字节读取,那么就会先读到char类型的数据,然后读取int型
数据的前三位,这是一次读取,然后再读取下一块内容,读取int型数据的最
后一位数据,最后如果要得到这个数据,计算机还要进行拼接操作,将之前
所读取到的三个字节和第二次读取到的一个字节拼接起来,才可以得到完整
的数字,而通过字节对齐的方式进行存储,虽然在空间上浪费,但是在时间
上却大大提高了效率,因此,这是一种牺牲空间换取时间的存储方式,提高
了存取数据的效率。

	对齐的原则为以下几点:
		1.第一个属性开始,从零开始计算偏移量
		2.第二个属性要放在,该属性大小与对齐模数(#pargama pack(n))相比,二者较小的那个值的整数倍。
		3.当所有属性计算完毕后,整体做二次偏移,将上有计算的结果(结构体整体的大小),扩充到 min(#pargama pack(n),这个结构体中最大的数据类型的大小)的整数倍上。
		也就是说,其实对齐就是以结构体中最大的数据类型为基准,其余的变量的存储都是以这个最大的数据类型的空间为准,能存储的下就存储,存储不下就开辟一块新的最大的数据类型的空间进行存储。

四、文件

流的概念
	
	流是一个动态的概念,可以将一个字节形象地比喻成一滴水,字节在设备、文件和程序之间的传输就是流,类似于水在管道中的传输,可以看出,流是对输入输出源的一种抽象,也是对传输信息的一种抽象。C语言中,I/O操作可以简单地看作是从程序移进或移出字节,这种搬运的过程便称为流(stream)。

文件指针	
	
	文件是由操作系统管理的单元。当我们想操作一个文件的时候,让操作系统帮我们打开文件,操作系统把我们指定要打开文件的信息保存起来,并且返回给我们一个指针指向文件的信息。文件指针也可以理解为代指打开的文件。这个指针的类型为FILE类型。该类型定义在stdio.h头文件中。通过文件指针,我们就可以对文件进行各种操作。
	
在VS中,文件指针的结构体如下所示:
struct _iobuf { 
        char  *_ptr;         //文件输入的下一个位置 
        int   _cnt;          //剩余多少字符未被读取
        char  *_base;        //指基础位置(应该是文件的其始位置) 
        int   _flag;         //文件标志 
        int   _file;         //文件的有效性验证 
        int   _charbuf;      //检查缓冲区状况,如果无缓冲区则不读取 
        int   _bufsiz;       //文件的大小 
        char  *_tmpfname;    //临时文件名 
}; 
在这里插入代码片typedef struct _iobuf FILE;

文件读写的注意事项

1.在进行单个字符(例如:getc、putc等函数的调用的时候)为什么不在读取单个字符的时候使用feof来进行判断是否到文件末尾呢?
编程过程中遇到此类问题,是feof的滞后性

解决办法如下所示的if代码
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

void test301()
{
	FILE* f = fopen("./test.txt", "r");
	if (NULL == f)
	{
		printf("打开文件失败!!");
		return;
	}
	char ch;
	while (!feof(f))
	{
		ch = fgetc(f);
		
		//解决feof的滞后性
		if (feof(f))
			break;

		printf("%c", ch);

	}
	//关闭文件
	fclose(f);
	f = NULL;
}

int main(void)
{
	test301();

	system("pause");
	return EXIT_SUCCESS;
}

文件操作复习:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

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

void test302()
{
	//写文件
	FILE* f_wirte = fopen("./test3.txt", "wb");
	if (f_wirte == NULL)
	{
		return;
	}

	struct Hero heros[] =
	{
		{ "孙悟空", 999 },
		{ "亚瑟", 20 },
		{ "曹操", 80 },
		{ "鲁班", 5 },
	};

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

	fclose(f_wirte);


	//读文件
	FILE* f_read = fopen("./test3.txt", "rb");

	if (f_read == NULL)
	{
		return;
	}

	struct Hero temp[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);

}


void test303()
{
	//写文件
	FILE* f_wirte = fopen("./test5.txt", "wb");
	if (f_wirte == NULL)
	{
		return;
	}

	struct Hero heros[] =
	{
		{ "孙悟空", 999 },
		{ "亚瑟", 20 },
		{ "曹操", 80 },
		{ "鲁班", 5 },
	};

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

	fclose(f_wirte);


	//读文件
	FILE* f_read = fopen("./test5.txt", "rb");
	if (f_read == NULL)
	{
		//error 宏
		//printf("文件加载失败\n");
		perror("文件加载失败"); //用户提示信息 + 系统提示信息

		return;
	}
	struct Hero tempHero;
	//移动光标
	// 参数1  文件指针   参数2 偏移大小    参数3  起始位置   
	// SEEK_SET 从开始  SEEK_END 从结尾   SEEK_CUR 从当前位置
	//fseek(f_read, sizeof(struct Hero) * 2, SEEK_SET);

	//移动光标到鲁班
	fseek(f_read, sizeof(struct Hero) * 3, SEEK_SET);

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

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

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


	fclose(f_read);
}

int main(void)
{
	
	//test302();
	test303();

	system("pause");
	return EXIT_SUCCESS;
}

五、配置文件读写(分文件编程)

配置文件读写.c

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"ConfigFile.h"


void test()
{
	char** fileData = NULL;
	int lines = 0;
	struct ConfigInfo* info = NULL;
	//加载配置文件
	loadFile_ConfigFile("./config.ini", &fileData, &lines);
	//解析配置文件
	parseFile_ConfigFile(fileData, lines, &info);
	char buf[64] = { 0 };
	while (1)
	{
		printf("请输入要查询的配置信息(输入“comm=exit”退出):");
		scanf("%s", buf);
		if (strncmp(buf, "comm=exit",9) == 0)
		{
			break;
		}
		printf("%s:%s\n", buf, getInfo_ConfigFile(buf, info, lines));
		getchar();
	}

	//释放配置文件信息
	destroInfo_ConfigFile(info);

}

int main(void)
{
	test();
	system("pause");
	return EXIT_SUCCESS;
}

ConfigFile.c

#include"ConfigFile.h"

//获取文件有效行数
int getLines_ConfigFile(FILE* file)
{
	char buf[1024] = { 0 };
	int lines = 0;
	while (fgets(buf, 1024, file) != NULL)
	{
		if (!isValid_ConfigFile(buf))
		{
			continue;
		}
		memset(buf, 0, 1024);
		++lines;
	}
	//把文件光标重置到文件开头
	fseek(file, 0, SEEK_SET);
	return lines;
}
//加载配置文件
void loadFile_ConfigFile(const char* filePath, char*** fileData, int* line)
{
	FILE* file = fopen(filePath, "r");
	if (!file)
	{
		printf("打开文件失败");
		return;
	}
	int lines = getLines_ConfigFile(file);

	//给每行数据开辟内存
	char** temp = malloc(sizeof(char*) * lines);

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

	while (fgets(buf, 1024, file) != NULL)
	{
		//如果返回false,表示该行为无效行
		if (!isValid_ConfigFile(buf))
		{
			continue;
		}
		temp[index] = malloc(strlen(buf) + 1);
		strcpy(temp[index], buf);
		++index;
		memset(buf, 0, 1024);

	}
	fclose(file);
	*fileData = temp;
	*line = lines;

}
//解析配置文件
void parseFile_ConfigFile(char** fileData, int lines, struct ConfigInfo** info)
{
	struct ConfigInfo* myinfo = malloc(sizeof(struct ConfigInfo) * lines);
	memset(myinfo, 0, sizeof(struct ConfigInfo) * lines);
	for (int i = 0; i < lines; ++i)
	{
		char* pos = strchr(fileData[i], ':');
		strncpy(myinfo[i].key, fileData[i], pos - fileData[i]);
		strncpy(myinfo[i].val, pos + 1, strlen(pos + 1) - 1);
		//printf("key:%s val:%s\n", myinfo[i].key, myinfo[i].val);
	}

	//释放文件信息
	
	for (int i = 0; i < lines; ++i)
	{
		if (fileData == NULL)
			break;
		if (fileData[i] != NULL)
		{
			free(fileData[i]);
			fileData[i] = NULL;
		}
	}
	free(fileData);
	fileData = NULL;

	*info = myinfo;
}
//获得指令配置信息
char* getInfo_ConfigFile(const char* key, struct ConfigInfo* info,int line)
{
	for (int i = 0; i < line; ++i)
	{
		if (strcmp(key, info[i].key) == 0)
		{
			return info[i].val;
		}
	}
	return  NULL;
}


//释放配置文件信息
void destroInfo_ConfigFile(struct ConfigInfo* info)
{
	if (NULL == info)
	{
		return;
	}
	free(info);
	info = NULL;
}


//判断当前行是否有效
int isValid_ConfigFile(const char* buf)
{
	if (buf[0] == '#' || buf[0] == '\n' || strchr(buf, ':') == NULL)
	{
		return 0;
	}
	return 1;
}

ConfigFile.h

#define _CRT_SECURE_NO_WARNINGS
#pragma once
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

struct ConfigInfo
{
	char key[64];
	char val[128];
};

//目的为了在C++中能够调用C写的函数
#ifdef __cplusplus
extern "C" {
#endif

	//获取文件有效行数
	int getLines_ConfigFile(FILE* file);
	//加载配置文件
	void loadFile_ConfigFile(const char* filePath, char*** fileData, int* line);
	//解析配置文件
	void parseFile_ConfigFile(char** fileData, int lines, struct ConfigInfo** info);
	//获得指令配置信息
	char* getInfo_ConfigFile(const char* key, struct ConfigInfo* info, int line);
	//释放配置文件信息
	void destroInfo_ConfigFile(struct ConfigInfo* info);
	//判断当前行是否有效
	int isValid_ConfigFile(const char* buf);

#ifdef __cplusplus
	}
#endif
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我! 毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip
综合小区管理系统管理系统按照操作主体分为管理员和用户。管理员的功能包括报修管理、车位管理、车位分配管理、出入管理、字典管理、房屋管理、物业费缴纳管理、公告管理、物业人员投诉管理、我的私信管理、物业人员管理、用户管理、管理员管理。用户的功能包括管理部门以及部门岗位信息,管理招聘信息,培训信息,薪资信息等。该系统采用了Mysql数据库,Java语言,Spring Boot框架等技术进行编程实现。 综合小区管理系统管理系统可以提高综合小区管理系统信息管理问题的解决效率,优化综合小区管理系统信息处理流程,保证综合小区管理系统信息数据的安全,它是一个非常可靠,非常安全的应用程序。 管理员权限操作的功能包括管理公告,管理综合小区管理系统信息,包括出入管理,报修管理,报修管理,物业费缴纳等,可以管理操作员。 出入管理界面,管理员在出入管理界面中可以对界面中显示,可以对招聘信息的招聘状态进行查看,可以添加新的招聘信息等。报修管理界面,管理员在报修管理界面中查看奖罚种类信息,奖罚描述信息,新增奖惩信息等。车位管理界面,管理员在车位管理界面中新增。公告管理界面,管理员在公告管理界面查看公告的工作状态,可以对公告的数据进行导出,可以添加新公告的信息,可以编辑公告信息,删除公告信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值