C语言结构体嵌套二级指针和文件读写相关函数
1.结构体嵌套二级指针#define _CRT_SECURE_NO_WARNINGS #include #include #include #include struct Teacher { char* name; char** Stduents; }; static void allocateSpace(struct Teacher***teachers) { struct Teacher** pArray = malloc(sizeof(struct Teacher) * 3); for (int i = 0; i < 3; i++) { //给每个老师分配空间 pArray[i] = malloc(sizeof(struct Teacher)); //给每个老师姓名分配空间 pArray[i]->name = malloc(sizeof(char) * 64); sprintf(pArray[i]->name, "Teacher_%d", i + 1); //给老师带的学生的数组分配空间 pArray[i]->Stduents = malloc(sizeof(char*) * 4); //给四个学生分配内存,并且赋值 for (int j = 0; j < 4; j++) { pArray[i]->Stduents[j] = malloc(sizeof(char) * 64); sprintf(pArray[i]->Stduents[j], "%s_Student_%d", pArray[i]->name, j + 1); } } *teachers = pArray; } void showArray(struct Teacher** pArray, int len) { for (int i = 0; i < len; i++) { printf("%s ", pArray[i]->name); for (int j = 0; j < 4; j++) { printf(" %s ", pArray[i]->Stduents[j]); } } } static void freeSpace(struct Teacher**pArray,int len) { for (int i = 0; i < len; i++) { //释放老师姓名 if (pArray[i]->name != NULL) { free(pArray[i]->name); pArray[i]->name = NULL; } //释放每个学生 for (int j = 0; j < len; j++) { if (pArray[i]->Stduents[j] != NULL) { free(pArray[i]->Stduents[j]); pArray[i]->Stduents = NULL; } } //释放学生数组 free(pArray[i]->Stduents); pArray[i]->Stduents = NULL; //释放老师 free(pArray[i]); pArray[i] = NULL; } //释放老师数组 free(pArray); pArray = NULL; } static void test01() { struct Teacher** pArray = NULL; //分配内存 allocateSpace(&pArray); //打印数组 showArray(pArray, 3); //释放内存 freeSpace(pArray, 3); pArray = NULL; } int main01() { test01(); return 0; } /* 打印结果 Teacher_1 Teacher_1_Student_1 Teacher_1_Student_2 Teacher_1_Student_3 Teacher_1_Student_4 Teacher_2 Teacher_2_Student_1 Teacher_2_Student_2 Teacher_2_Student_3 Teacher_2_Student_4 Teacher_3 Teacher_3_Student_1 Teacher_3_Student_2 Teacher_3_Student_3 Teacher_3_Student_4 */
2.结构体偏移量#define _CRT_SECURE_NO_WARNINGS #include #include #include #include struct person { char a;//0~3 int b;//4~7 }; static void test01() { struct person p1; struct person* p = &p1; printf("b的偏移量为:%d ", (int)&(p->b) - (int)p); printf("b的偏移量为:%d ", offsetof(struct person, b)); } //通过偏移量获取数据 static void test02() { struct person p1 = { "a",10 }; printf("p.b=%d ", *(int*)((char*)&p1 + offsetof(struct person, b))); printf("p.b=%d ", *(int*)((int*)&p1 + 1)); } //结构体嵌套结构体 struct person2 { char a; int b; struct person c; }; static void test03() { struct person2 p = { "a",10,"b",20 }; int offset1 = offsetof(struct person2, c); int offset2 = offsetof(struct person, b); printf("%d ", *(int*)((char*)&p + offset1 + offset2));//10 printf("%d ", ((struct person*) ((char*)&p + offset1))->b);//10 } int main02() { //test01(); test02(); return 0; }
3.内存的对齐方式#define _CRT_SECURE_NO_WARNINGS #include #include #include #include //#pragma pack(1) 对齐模式修改为1 #pragma pack(show)//默认对齐模数为8 该值可以改为2的n次方 //对于自定义数据类型 内存的对齐规则: /* 1、从第一个属性开始 偏移为0 2、第二个属性开始,地址要放在该类型的整数倍, 与对齐模数比 取小的值 的整数倍上。 3、所有的属性都计算结束后,整体做二次对齐, 整体需放在属性中最大类型与对齐模数比取小的值的整数倍上。 */ typedef struct _STUDENT { int a; char b; double c; float d; }Student static void test01() { printf("sizeof=%d ", sizeof(Student));//24 } //结构体嵌套结构体时,只需看子结构体中最大数据类型即可 typedef struct _STUDENT2 { char a;//0~7 Student b;//8~31 子结构体最大数据类型是8 double c;//32~39 }Student2; static void test02() { printf("sizeof=%d ", sizeof(Student2)); } int main03() { //test01(); test02(); return 0; }
4.文件的读写
fgetc、fputc、fgets、fputs、fread、fwrite、fprintf、fscanf等函数的使用#define _CRT_SECURE_NO_WARNINGS #include #include #include #include //1、字符的读写回顾 fgetc()、fputc() static void test01() { //写文件 fputc FILE* f_write = fopen("f:/a.txt", "w"); if (f_write == NULL) { return; } char buf[] = "hello world"; for (int i = 0; i < strlen(buf); i++) { fputc(buf[i], f_write); } fclose(f_write); //读文件 fgetc FILE* f_read = fopen("f:/a.txt", "r"); if (f_read == NULL) { return; } char ch; while ((ch = fgetc(f_read) != EOF))//EOF即 END OF FILE { printf("%c ", ch); } fclose(f_read); } //2、按行读写文件 static void test02() { //写文件 fputs() FILE* f_write = fopen("f:/a.txt", "w+"); if (f_write == NULL) { return; } char* buf[] = { "君不见黄河之水天上来,奔流到海不复回 " "君不见高堂明镜悲白发,朝如青丝暮成雪 " "人生得意须尽欢,莫使金樽空对月 " "天生我材必有用,千金散尽还复来 " }; for (int i = 0; i < 4; i++) { fputs(buf[i], f_write); } fclose(f_write); //读文件 fgets() FILE* f_read = fopen("f:/a.txt", "r"); if (f_read == NULL) { return; } while (!feof(f_read)) { char temp[1024] = { 0 }; fgets(temp, 1024, f_read); printf("%s ", temp); } fclose(f_read); } //3、按块进行读写 fread()、fwrite() struct hero { char name[64]; int age; }; static void test03() { //写文件 fwrite() FILE* f_write = fopen("f:/a.txt", "wb"); if (f_write == NULL) { return; } struct hero heros[] = { {"孙悟空",111}, {"曹操",222}, {"赵云",333}, {"鲁班",444}, }; for(int i=0;i<4;i++) { fwrite(&heros[i], sizeof(struct hero), 1, f_write); } fclose(f_write); //读文件 fread() FILE* f_read = fopen("f:/a.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 ", temp[i].name, temp[i].age); } fclose(f_read); } //4、格式化读写 static void test04() { //写文件 fprintf() FILE* f_write = fopen("f:/a.txt", "w"); if (f_write = NULL) { return; } fprintf(f_write, "hello world %s", "abcd"); fclose(f_write); //读文件 fscanf() FILE* f_read = fopen("f:/a.txt", "r"); if (f_read = NULL) { return; } char temp[1024] = { 0 }; while (!feof(f_read)) { fscanf(f_read, "%s", temp); printf("%s ", temp); } fclose(f_read); } static void test05() { //写文件 FILE* f_write = fopen("f:/a.txt", "wb"); if (f_write == NULL) { return; } struct hero heros[] = { {"孙悟空",111}, {"曹操",222}, {"赵云",333}, {"鲁班",444}, }; for (int i = 0; i < 4; i++) { fwrite(&heros[i], sizeof(struct hero), 1, f_write); } fclose(f_write); //读文件 FILE* f_read = fopen("f:/a.txt", "rb"); if (f_read == NULL) { //error 宏 //printf("文件加载失败 "); perror("文件加载失败");//用户提示信息+系统提供信息 return; } struct hero temphero; //移动光标 //fseek(f_read, sizeof(struct hero) * 3, SEEK_SET); fseek(f_read, -(long)sizeof(struct hero) * 1, SEEK_END);//sizeof的返回值是无符号的 需强转为long类型 rewind(f_read);//将光标置到文件开头 fread(&temphero, sizeof(struct hero), 1, f_read); printf("姓名:%s,年龄:%d ", temphero.name, temphero.age);//鲁班 444 fclose(f_read); } int main04() { //test01(); //test02(); //test03(); //test04(); test05(); return 0; }
5.文件读写的注意事项#define _CRT_SECURE_NO_WARNINGS #include #include #include #include static void test01() { FILE* file = fopen("f:/a.txt", "r"); if (file == NULL) { return; } char ch; #if 0 while (!feof(file)) { ch = fgetc(file); //滞后性 if (feof(file)) { break; } printf("%c", ch); } #endif char ch; while ((ch = fgetc(file)) != EOF) { printf("%c", ch); } fclose(file); } //注意事项2 struct person { char* name;//不要将指针写入到文件中 int age; }; int main05() { test01(); return 0; }
6.配置文件的读写#pragma once #define _CRT_SECURE_NO_WARNINGS #include #include #include struct ConfigInfo { char key[64]; //索引值 char value[64]; //实值 }; //获取有效行数 int getFileLine(char* fileName); //判断当前行是否有效 int isValidLine(char* str); //解析文件 void parseFile(char* filePath, int lines, struct ConfigInfo** configInfo); //根据索引值 获取 实值 char* getInfoByKey(char* key, struct ConfigInfo* configInfo, int line); //释放信息 void freeSpace(struct ConfigInfo* configInfo); #include "config.h" //获取有效行数 int getFileLine(char* fileName) { FILE* file = fopen(fileName, "r"); if (file == NULL) { return -1; } char buf[1024] = { 0 }; int lines = 0; while (fgets(buf, 1024, file) != NULL) { //如果是有效行 才统计 if (isValidLine(buf)) { lines++; } } fclose(file); return lines; } //判断当前行是否有效 int isValidLine(char* str) { if (str[0] == " " || str[0] == " " || 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"); char buf[1024] = { 0 }; int index = 0; while (fgets(buf, 1024, file) != NULL) { //解析数据 有效数据才解析 // heroName:aaaa if (isValidLine(buf)) { memset(info[index].key, 0, 64); memset(info[index].value, 0, 64); char* pos = strchr(buf, ":"); //pos代表冒号所在位置 strncpy(info[index].key, buf, pos - buf); //将key截取到 结构体中 最后-1的原因是不需要截取换行符 strncpy(info[index].value, pos + 1, strlen(pos + 1) - 1); /*printf("key = %s ", info[index].key); printf("value = %s", info[index].value);*/ index++; } memset(buf, 0, 1024); } *configInfo = info; } //根据索引值 获取 实值 char* getInfoByKey(char* key, struct ConfigInfo* configInfo, int line) { for (int i = 0; i < line; i++) { if (strcmp(key, configInfo[i].key) == 0) { return configInfo[i].value; } } return NULL; } //释放信息 void freeSpace(struct ConfigInfo* configInfo) { if (configInfo != NULL) { free(configInfo); configInfo = NULL; } }#define _CRT_SECURE_NO_WARNINGS #include #include #include #include "config.h" struct Person { char a; int b; }; void test01() { char* filePath = "./config.txt"; int line = getFileLine(filePath); printf("文件的有效行数为:%d ", line); struct ConfigInfo* pArray = NULL; parseFile(filePath, line, &pArray); //测试 根据key 访问value printf("heroId = %s ", getInfoByKey("heroId", pArray, line)); printf("heroName = %s ", getInfoByKey("heroName", pArray, line)); printf("heroAtk = %s ", getInfoByKey("heroAtk", pArray, line)); printf("heroDef = %s ", getInfoByKey("heroDef", pArray, line)); printf("heroInfo = %s ", getInfoByKey("heroInfo", pArray, line)); //释放内存 freeSpace(pArray); pArray = NULL; //文件加密 codeFile( sourceFile , destFile ) // # 35 转为 short // 0000 0000 0010 0011 << 4 // 0000 0010 0011 0000 // 1000 0000 0000 0000 | // 1000 0010 0011 0000 + 0000 ~ 1111 随机数 rand()%16 0~ 15 // 1000 0010 0011 1010 //解密 decodeFile ( sourceFile , destFile ) // 1000 0010 0011 1010 <<1 // 000 0010 0011 10100 >> 5 // 0000 0000 0010 0011 } int main() { test01(); system("pause"); return EXIT_SUCCESS; }