1.结构体嵌套二级指针
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
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\n", pArray[i]->name);
for (int j = 0; j < 4; j++)
{
printf(" %s\n", 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<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<stddef.h>
struct person
{
char a;//0~3
int b;//4~7
};
static void test01()
{
struct person p1;
struct person* p = &p1;
printf("b的偏移量为:%d\n", (int)&(p->b) - (int)p);
printf("b的偏移量为:%d\n", offsetof(struct person, b));
}
//通过偏移量获取数据
static void test02()
{
struct person p1 = { 'a',10 };
printf("p.b=%d\n", *(int*)((char*)&p1 + offsetof(struct person, b)));
printf("p.b=%d\n", *(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\n", *(int*)((char*)&p + offset1 + offset2));//10
printf("%d\n", ((struct person*) ((char*)&p + offset1))->b);//10
}
int main02()
{
//test01();
test02();
return 0;
}
3.内存的对齐方式
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
//#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\n", 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\n", sizeof(Student2));
}
int main03()
{
//test01();
test02();
return 0;
}
4.文件的读写
fgetc、fputc、fgets、fputs、fread、fwrite、fprintf、fscanf等函数的使用
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
//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\n", ch);
}
fclose(f_read);
}
//2、按行读写文件
static void test02()
{
//写文件 fputs()
FILE* f_write = fopen("f:/a.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);
//读文件 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\n", 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\n", 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\n", 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("文件加载失败\n");
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\n", temphero.name, temphero.age);//鲁班 444
fclose(f_read);
}
int main04()
{
//test01();
//test02();
//test03();
//test04();
test05();
return 0;
}
5.文件读写的注意事项
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
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<stdio.h>
#include<string.h>
#include<stdlib.h>
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] == '\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\n
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\n", 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<stdio.h>
#include<string.h>
#include<stdlib.h>
#include "config.h"
struct Person
{
char a;
int b;
};
void test01()
{
char* filePath = "./config.txt";
int line = getFileLine(filePath);
printf("文件的有效行数为:%d\n", line);
struct ConfigInfo* pArray = NULL;
parseFile(filePath, line, &pArray);
//测试 根据key 访问value
printf("heroId = %s\n", getInfoByKey("heroId", pArray, line));
printf("heroName = %s\n", getInfoByKey("heroName", pArray, line));
printf("heroAtk = %s\n", getInfoByKey("heroAtk", pArray, line));
printf("heroDef = %s\n", getInfoByKey("heroDef", pArray, line));
printf("heroInfo = %s\n", 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;
}