C语言提高 (5) 第五天 结构体,结构体对齐 文件
1昨日回顾
2作业讲解
3 结构体的基本定义
//1
struct teacher
{
int id;
char name[64];
};
struct teacher t5 = { 5, "laoshi5" };
//2
struct {
int id;
char name[64];
} t3, t4;//匿名的结构体类型 类型只能定义一次, 不能通过函数传参
//3
typedef struct _teacher
{
int id;
char name[64];
} teacher_t; //最常用的写法
/*
struct _teacher
{
int id;
char name[64];
};
typedef struct _teacher teacher_t;
*/
void print_teacher(struct teacher* p1)
{
printf("id = %d\n", p1->id);
printf("name = %s\n", p1->name);
}
void print_teacher2(struct teacher t) //t = t1 int a = b; struct teacher t1 = t2
{
printf("===== print_teacher2===\n");
printf("id = %d\n", t.id);
printf("name = %d\n", t.name);
}
void copy(struct teacher to, struct teacher from)
{
to = from;
}
void copy2(struct teacher *to, struct teacher *from)
{
*to = *from;
}
/*
void print_teacher2(struct {
int id;
char name[64];
})
*/
int main(void)
{
struct teacher t1;
struct teacher t8;
teacher_t t6 = {6, "laoshi6"};
//teacher t7; // C语言中 定义一个结构体 必须加上struct 关键字 C++不用加
t1.id = 10;
strcpy(t1.name, "laoshi1");
print_teacher(&t1);
print_teacher(&t5);
print_teacher2(t1); //
printf("=====\n");
copy2(&t8, &t1);
print_teacher(&t8);
struct teacher t9 = t1; //int a = b;
return 0;
}
4 结构体作为函数参数
5结构体嵌套一级指针

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NAME_LEN (64)
struct teacher
{
int id;
char *name;
};
int create_teachers(struct teacher **tpp, int num)
{
if (tpp == NULL) return;
struct teacher *tp;
int i = 0;
// 在堆上分配空间
tp = (struct teacher*) malloc(sizeof(struct teacher)* num);
if (tp == NULL)
{
fprintf(stderr, "malloc tp error\n");
return -1;
}
memset(tp, 0, sizeof(struct teacher) * num);
for (i = 0; i < num; i++)
{
// 在堆上给name分配空间
tp[i].name = (char *)malloc(sizeof(char)*NAME_LEN);
memset(tp[i].name, 0, sizeof(char)*NAME_LEN);
}
// 开辟完之后把指针传出去
*tpp = tp;
return 0;
}
void sort_teacher(struct teacher *tp,int num)
{
int i = 0;
int j = 0;
struct teacher temp_teacher;
for (i = 0;i<num-1;i++)
{
for (j = i; j < num; j++)
{
// 每次把最小的放到数组最开始的位置
if (tp[i].id > tp[j].id) {
temp_teacher = tp[i];
tp[i] = tp[j];
tp[j] = temp_teacher;
}
}
}
}
void print_teacher(struct teacher* p, int num)
{
int i = 0;
for (i = 0; i < num; i++)
{
printf("=========\n");
printf("id:%d\n", p[i].id);
printf("name:%s\n", p[i].name);
}
}
// 内存释放
void free_teachers(struct teacher **tpp,int num)
{
if (tpp == NULL)
{
return;
}
struct teacher *tp = *tpp;
int i = 0;
if (tp != NULL)
{
for (i = 0; i < num; i++) {
if (tp[i].name != NULL)
{
free(tp[i].name);
tp[i].name = NULL;
}
}
free(tp);
*tpp = NULL;
printf("free success\n");
}
}
int main(int argc,char* argv[])
{
// 创建两个老师
// 创建结构体指针
struct teacher *tp = NULL;
int num = 2;
int i = 0;
int ret = 0;
// 传入指针,通过二级指针接收来对此指针所指向内存区域进行修改
ret = create_teachers(&tp, num);
if (ret < 0) return -1;
// 为堆上的name的位置赋值
for (i = 0; i < num; i++)
{
printf("enter tp[%d]'s id :", i);
scanf("%d", &tp[i].id);
printf("enter tp[%d]'s name :", i);
scanf("%s", tp[i].name);
}
print_teacher(tp, num);
sort_teacher(tp, num);
print_teacher(tp, num);
free_teachers(&tp, num);
return 0;
}
6结构体深拷贝和浅拷贝问题
// 结构体可以通过变量直接赋值,但不要使用这种方法
// 要给结构体中的成员 一个一个的拷贝
如果结构体中有指针,浅拷贝后可能会造成重复释放的问题
7结构体内部成员的偏移量


偏移:



8中午回顾
9结构体嵌套二级指针开辟内存空间
10结构体嵌套二级指针释放空间
11结构体字节对齐
举个例子:
|
1 2 3 4 5 6 |
struct { char a; //1byte int b; //4byte char c[2] //2byte double d; //8byte }Struct_A; |
在计算机内存中,结构体变量的存储通常是按字长对齐的,比如8位机里就按字节对齐,那么上述结构体共占用1+4+2+8=15byte。
在16位机里,变量就按照2字节对齐,比如a这个成员,虽然是个char类型,地址在0x80000000本身只占1字节,但是下一个成员b却不能使用0x80000001这个地址,而必须使用0x80000002,这就是按字长对齐。以上结构体占用的空间也就是2+4+2+8=16字节
同理,在32位机中,如果a在0x80000000的话,b只能放在0x80000004,因为这里的字长是4个字节。以上结构体占用空间4+4+4+8=20字节
也就是说总有一些字节是浪费掉的,这样做的目的很简单,就是因为在大多数计算机体系结构中,对内存操作时按整字存取才能达到最高效率,相当于是以空间换取时间。当然在某些计算机体系结构中,比如ARM,是支持非对齐字传输的,也就是说变量并不一定要按照字长对齐,尽管这样可能会降低效率,但换来的是存储空间上的节约。对于程序员来讲,则需要将结构体声明为紧凑型结构体。声明的关键字依编译器不同而异,你可以去查一下__packed关键字,可以得到更详细的说明。使用紧凑型结构体,则会强制编译器将结构体成员按1字节对齐,则以上结构体占用空间仍为15字节。

资料:
https://bbs.csdn.net/topics/392057821
12不完整类型字节序对齐




13位移操作符


14掩码
~按位取反运算符



题目:从八位开始找四位。。。这个函数实现


0按位取反编程全1 然后向左偏移n位 然后再全部取反 与 源数据x向右偏移position位 相与
?
9.文件的操作
mysql oracle 存到硬盘中的数据库
redis mongodb 内存型数据库





(缓冲区满了以后刷新缓冲区,存到文件中

cpu在不同进程间不停切换 ,如果没有缓冲区 cpu直接把100k放到磁盘中,然后切换进程2 然后切换进程1
现在有了缓冲区,cpu可以先把100k放到内存中(很快),然后就可以去切换进程2,后面让内存与磁盘进行交互io 效率提升
文件结构体:

操作系统通过限制文件描述符fd的数目来限制打开文件的个数



standard C I/O
fputc:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define FILE_NAME "C:/Users/lg/Desktop/1.txt"
// 字符的写操作
void test_write_char()
{
char *buf = "abcdefghij";
int i = 0;
FILE *fp = fopen(FILE_NAME, "w+");
if (fp == NULL) {
fprintf(stderr, "open %s error \n", FILE_NAME);
return -1;
}
for (i = 0; i < (int)strlen(buf); i++)
{
if (fputc(buf[i], fp) == EOF) {
fprintf(stderr, "fput %c error\n", buf[i]);
break;
}
}
if (fp != NULL)
{
fclose(fp);
}
return 0;
}
int test_read_char()
{
FILE *fp = NULL;
char buf[128] = { 0 };
char ch = 0;
int i = 0;
fp = fopen(FILE_NAME, "r+");
if (fp == NULL)
{
fprintf(stderr, "fopen %s error\n",FILE_NAME);
}
while ( (ch = fgetc(fp)) != EOF)
{
buf[i] = ch;
i++;
}
printf("buf:%s\n",buf);
if (fp != NULL)
{
fclose(fp);
}
return 0;
}
int main(void)
{
test_write_char();
test_read_char();
return 0;
}
fputs fgets: 操作str
fputs不会把’\n’写进去

注意:1.fputs不会把字符串的\0写进去
2.fputs不会写\n

注意:fgets不是根据\0来从文件区分一行,而是通过\n,并会把\n读进去



总结一下:
int fputc(ch,fp) (返回值是字符ascii码)
int fgetc(fp) (返回值是字符ascii 码)
int fputs(buf,fp)
char * fgets(buf,len,fp)
文件的随机存取操作
ftell
fseek
配置文件的测试框架
多文件形式编程
配置文件的写配置实现
C语言提高 (5) 第五天 结构体,结构体对齐 文件的更多相关文章
- C语言第五次作业——循环结构
C语言程序设计第五次作业--循环结构(1) (一)改错题 输出华氏摄氏温度转换表:输入两个整数lower和upper,输出一张华氏摄氏温度转换表,华氏温度的取值范围是{lower,upper},每次增 ...
- C语言之结构体内存的对齐
C语言之结构体内存的对齐 大纲: 零.引例 一.结构体内存对齐规则 二.怎样计算结构体的大小 三.设计结构体时要注意的方面 四.为什么存在内存对齐 五.修改默认对齐数 在前面的章节中,我们谈到了C ...
- GO语言的进阶之路-go的程序结构以及包简介
GO语言的进阶之路-go的程序结构以及包简介 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.编辑,编译和运行 A,编辑 Go程序使用UTF-8编码的纯Unicode文本编写.大 ...
- C语言结构体的内存对齐问题
在C语言开发当中会遇到这样的情况: #include <stdio.h> struct test { int a; char b; }; int main(int argc, const ...
- C语言实现GBK/GB2312/五大码之间的转换(转)
源:C语言实现GBK/GB2312/五大码之间的转换 //----------------------------------------------------------------------- ...
- C语言高级-结构,共用体,文件,链表
C语言结构 标准声明方式 struct student{ int age; char sex; }; 这个可以在main函数中定义: struct student ...
- C语言结构体的字节对齐原则
为什么要对齐? 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据 ...
- C语言高速入门系列(五)
C语言高速入门系列(五) C语言指针初涉 ------转载请注明出处:coder-pig 本节引言: 上一节我们对C ...
- C语言实现使用动态数组来构造栈结构
我在面前一篇博客<C语言实现使用静态数组来构造栈结构>中使用了静态数组来模拟栈的操作.静态数组的大小是在代码中写死的.是存储在用户栈上面的,使用起来不灵活.在这篇博客中我会使用动态数组来构 ...
随机推荐
- DJANGO之自定义模板过滤器
我查找了DJANGO模板的过滤器,好像指定字符串包含指定关-键字符的过滤器没有呢, 没有硬着头-皮,按网上其它人的作法,写了一个,成功了...:) 参考URL: http://liuzhijun.it ...
- ASP.NET--常用ORM框架
subsonic massive dapper 性能不错,接近原声的ADO.NET 这个是大家推荐的,stackoverflow用的就是这个框架 petapoco 这些都是ORM框架
- CentOS 6.9安装过程
下载: https://wiki.centos.org/Download 安装过程: 分区方案一: 以下为大概的分区步骤,根据实际需要进行分配: 最终分区的配置大小如下所示: 推荐更详细的分区方案,参 ...
- HDU 2457
直接从root遍历扩展DP,当扩展到的字母和字符串字母相同时,不用修改,不同时,要求修改加1 注意不要扩展危险结点. #include <iostream> #include <cs ...
- Android 最新面试题
1. Intent的几种有关Activity启动的方式有哪些,你了解每一个含义吗? Intent的一些标记有FLAG_ACTIVITY_BROUGHT_TO_FRONT .FLAG_ACTIVITY_ ...
- BEGINNING SHAREPOINT® 2013 DEVELOPMENT 第12章节--SP 2013中远程Event Receivers 总结
BEGINNING SHAREPOINT® 2013 DEVELOPMENT 第12章节--SP 2013中远程Event Receivers 总结 本章节向你介绍了SP平台上eve ...
- sikuli+eclipse实例
设置sikuli环境变量 如果在执行脚本的时候出现以下错误: Getting the VisionProxy.dll: Can not find dependent libraries... 把Sik ...
- BZOJ 1005 [HNOI2008]明明的烦恼 purfer序列,排列组合
1005: [HNOI2008]明明的烦恼 Description 自从明明学了树的结构,就对奇怪的树产生了兴趣......给出标号为1到N的点,以及某些点最终的度数,允许在任意两点间连线,可产生多少 ...
- 基于aspectj的aop的操作
1.引入相关的jar包 2.建两个类 public class Book { public void add(){ System.out.println("add-----------&qu ...
- C语言 - typedef struct 与struct
c语言中可以选择的数据类型太少了. Java中有一些高级的数据结构. 结构中能够存放基本的数据类型以及其他的结构. 结构定义,一般放在程序的开头部分. 一般放在include之后. #include ...