Cday05---文件操作

1. 数组名

printArr1(int* arr, int len);
printArr2(int(*arr)[3], int len);
printArr3(char** arr, int len);
void test() {
	//默认情况下数组名指向首元素地址,当取地址后指针指向整个数组
	//如果只需要打印数组元素,是否取地址都可以。但如果要操控地址时,
	//指向整个数组的指针的步长不满足要求 
	int arr1[10];//arr1的类型为int*
	int arr2[3][3] = {
		{1,2,3},
		{4,5,6},
		{7,8,9},
	};//arr2的类型为int(*)[3];

	char* arr3[] = { "aaa","bbb","ccc" };//arr3的类型为char**
	char** arr4[3];//arr4的类型为char***,指向一维数组
}
void test() {
	typedef int(ARRAY_TYPE)[10];
	typedef int(*ARRAY_POINTER_TYPE)[10];
	int arr1[10];
	int arr2[11];
	ARRAY_TYPE* p1 = &arr1;
	ARRAY_POINTER_TYPE p2 = &arr1;
	int(*p3)[10] = &arr1;
}

2.结构体嵌套二级指针

在这里插入图片描述

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

int allocateSpace(struct Teacher*** t) {
	if (NULL == t)
		return -1;//错误码,不同错误码表示不同错误
	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_stu_%d", ts[i]->name, j + 1);
		}
	}
	*t = ts;
	return 0;
}

void printT(struct Teacher** teachers) {
	if (NULL == teachers)
		return;
	for (int i = 0; i < 3; ++i) {
		printf("%s\n", teachers[i]->name);
		for (int j = 0; j < 4; ++j) {
			printf("    %s\n", teachers[i]->students[j]);
		}
	}
}

void freeSpace(struct Teacher** teachers) {
	if (NULL == teachers)
		return;
	for (int i = 0; i < 3; ++i) {
		if (teachers[i] == NULL)
			continue;
		if (teachers[i]->name != NULL) {
			free(teachers[i]->name);
			teachers[i]->name = NULL;
		}
		for (int j = 0; j < 4; ++j) {
			if (teachers[i]->students[j] != NULL) {
				free(teachers[i]->students[j]);
				teachers[i]->students[j] = NULL;
			}
		}
		free(teachers[i]->students);
		teachers[i]->students = NULL;

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

void test() {
	struct Teacher** teachers = NULL;//teachers为二级指针
	int ret = 0;
	ret = allocateSpace(&teachers);
	if (ret < 0) {
		printf("allocateSpace调用出错");
		return;
	}
	//打印
	printT(teachers);
	//释放内存
	freeSpace(teachers);
	teachers = NULL;
}

在这里插入图片描述

3.结构体偏移量

#include <stddef.h>//可计算偏移量
struct A {
	char a1;
	int a2;
};

void test() {
	struct A a = { 'b',20 };
	//&a可以拿到结构体首地址
	//char *改变了指针类型,即改变了步长
	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;
	int b;
	struct C c;
};

void test() {
	struct B b = { 'a',20,30,3.14 };
	int off1 = offsetof(struct B, c);
	int off2 = offsetof(struct C, b);
	printf("%f\n", *(double*)(((char*)&b + off1) + off2));
	printf("%d\n", &(b.c.b));
	printf("%f\n", ((struct C*)((char*)&b + off1))->b);
}

在这里插入图片描述

4.内存字节对齐

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
手动设置对齐模数
在这里插入图片描述

//第一个元素偏移量为0
//从第二个元素开始计算偏移量
//结构体总的大小必须是内部最大成员的整数倍
struct Student {
	int a;//0-3
	char b;//4-7
	double c;//8-15
	float d;//16-19
};

void test() {
	printf("%d\n", sizeof(struct Student));
}

在这里插入图片描述

5.文件IO

在这里插入图片描述
流的定义
在这里插入图片描述
文本流
在这里插入图片描述
在这里插入图片描述
二进制流
在这里插入图片描述
在这里插入图片描述

void test() {
	FILE *fp = fopen("./test.txt", "r");
	if (NULL == fp) {
		printf("打开文件失败");
		return;
	}
	char ch;
	while (!feof(fp))
	{
		ch = fgetc(fp);
		if (feof(fp))
			break;//将读到的结尾标志删除
		printf("%c", ch);
	}
	//关闭文件
	fclose(fp);
	fp = NULL;
}

在这里插入图片描述

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

6.配置文件读写

在这里插入图片描述

//configFIle.h
//防止头文件重复包含
#pragma once
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>//可计算偏移量

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

//为了在C++中能调用C写的函数
#ifdef __cplusplus
	extern "C" {
#endif
		//获得文件有效行数
		int gelines_configFile(FILE* fp);
		//加载配置文件
		void loadFile_configFile(const char* filepath, char ***fileData, int *lines);
		//解析配置文件
		void parseFile(char** fileData, int lines, struct configInfo** info);
		//获得指定配置信息
		char* getInfo(const char* key, struct configInfo* info, int line);
		//释放配置文件信息
		void destroyInfo(struct configInfo* info);
		//判断当前行是否有效
		int isValid(const char* buf);
#ifdef __cplusplus
	}
#endif
//configFIle.c
#define _CRT_SECURE_NO_WARNINGS
#include "configFile.h"

//获得文件有效行数
int gelines_configFile(FILE* fp) {
	char buf[1024] = { 0 };
	int lines = 0;
	while (fgets(buf, 1024, fp) != NULL) {
		if (!isValid(buf))
			continue;
		memset(buf, 0, 1024);
		++lines;
	}
	//把文件指针重置到文件开头
	fseek(fp, 0, SEEK_SET);
	return lines;
}
//加载配置文件
void loadFile_configFile(const char* filepath, char*** fileData, int* line) {
	FILE* file = fopen(filepath, "r");
	if (NULL == file)
		return;
	//先获取行数
	int lines = gelines_configFile(file);
	//给每行数据开辟内存
	char** temp = malloc(sizeof(char*) * lines);
	//读取数据
	char buf[1024] = { 0 };
	int index = 0;
	while (fgets(buf, 1024, file) != NULL) {
		if (!isValid(buf)) {
			//如果返回false
			continue;
		}
		temp[index] = malloc(strlen(buf) + 1);
		strcpy(temp[index], buf);
		index++;
		//清空buf
		memset(buf, 0, 1024);
	}
	//关闭文件
	fclose(file);
	file = NULL;
	*fileData = temp;
	*line = lines;
}
//解析配置文件
void parseFile(char** fileData, int lines, struct configInfo** info) {
	struct configInfo* infos = malloc(sizeof(struct configInfo) * lines);
	memset(infos, 0, sizeof(struct configInfo) * lines);
	for (int i = 0; i < lines; ++i) {
		//分割冒号的前后部分
		char* pos = strchr(fileData[i], ':');
		strncpy(infos[i].key, fileData[i], pos - fileData[i]);
		strncpy(infos[i].val, pos + 1, strlen(pos + 1) - 1);
		//printf("key:%s val:%s\n", infos[i].key, infos[i].val);
	}

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

	*info = infos;
}
//获得指定配置信息
char* getInfo(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 destroyInfo(struct configInfo* info) {
	if (NULL == info)
		return;
	free(info);
	info = NULL;
}
//判断当前行是否有效
int isValid(const char* buf) {
	if (buf[0] == '#' || buf[0] == '\n' || strchr(buf, ':') == NULL) {
		return 0;
	}
	return 1;
}
//main.c
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>//可计算偏移量
#include "configFile.h"

void test() {
	char** fileData = NULL;
	int lines = 0;
	struct configInfo* info = NULL;
	//加载配置文件
	loadFile_configFile("./config.ini", &fileData, &lines);
	//解析配置文件
	parseFile(fileData, lines, &info);
	//printf("lines:%d\n", lines);
	printf("IP:%s\n", getInfo("ip", info, lines));
	//释放配置信息内存
	destroyInfo(info);
}

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

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值