sizeof()
sizeof 求字节运算符
sizeof x
sizeof(x)
用来求一个对象或类型所占字节数的运算符
x可以是一个对象,也可以是一个类型
sizeof(x): 求x所占的内存的字节数
x可以是一个对象(变量,数组......)也可以是一个类型
x可以不存在,只要typeof(x)可以确定就oksizeof(x) : 先求x的类型,然后再求该类型所占的字节数
结构体
问题的一个引入
”建模“ : 建立模型 为什么需要建模?? 问题域(问题空间): 跟问题本身相关一些因素,元素,条件等等这些 分析问题,需求,目标 算法思路(解决问题的一些步骤) 解决方案域(解空间): 与具体的解决问题的方式,方法相关的一些因素,条件 如: 数学---》数学方法(公式,方程,。。。。。) C语言 ---> 算法的模型,存储类型,变量,语法.... 问题域 -----> 解决方案域 把问题域里面的一些元素转换成解决方案域的元素 这个过程,建模 ”人“ : 在解决方案域(C)用什么来描述的??? 现实生活中的物体需要抽象成计算机语言中的数据类型(对象) 物体的属性: 学生: 学号 ----> int num 姓名 ----> char name[32]; 性别 ----> char gender; //'1''0' 年龄 ----> int age; 地址 ----> char addr[32]; ..... ====> 把这些物品的属性组合到一个数据类型当中去,用来表示”学生“ C语言允许程序员定义自己的组合类型: 结构体 共用体 枚举结构体 : 自定义的一种组合类型
定义:
struct 结构体名 { 成员类型1 成员名1; 成员类型2 成员名2; ....... 成员类型n 成员名n; }; 结构体类型是由多个成员构成的,而且每一个成员都有自己的类型(只要是合法的类型就可以), 当然不同的成员,它的类型也是可以相同的,但是成员名不能一样。 ”结构体名“ : 符合C语言关于标识符的规定 struct 结构体 => 你定义的新类型的名字。 如: struct student {}; struct student zyz; "成员类型1" 、 "成员类型2" 、 。。。。。 "成员类型n": 只要是C语言中合法的类型都可以(基本类型,构造类型,指针......) "成员名1"、"成员名2"、。。。。。。、"成员名n": 要符合C语言中标识符的规定就可以了 例子: struct student { int num; char name[32]; char gender; int age; float score; }; 上面定义了一个新的类型 : struct student 并且这个新的类型里面包括:num name gender age score这些成员变量 如何定义一个新类型的变量: 变量的定义: 变量的类型 变量名= {初始值}; struct student zyz; zyz 里面就会有一个int类型的num....... 那么这些成员变量在内存当中是如何分布的呢??结构体成员的内存布局
(1)、结构体类型所占空间是各成员变量所占的空间之和 (2)、结构体内各成员变量按他们所定义时出现的次序,依次保存结构体变量的引用
结构体的内部的成员变量的引用 (1)、 . 域操作符:取某个子成员变量 结构体变量名.成员变量名 =>取结构体变量内部的成员变量 例子: struct student s; s.num; s.age; ...... 引用成员变量和普通变量一样,有左值,右值 s.age = 20; int b = s.age;
scanf("%d",&(s.age)); //struct student *p = malloc(sizeof(*p)); struct student *p = malloc(sizeof(struct student)); p 就指向struct student 一个对象 *p => 指向的那个对象(结构体变量)。 (*p).age; (*p).num; (*结构体指针).成员变量(2)、-> 结构体指针->成员变量 如: p->age; p->num; p->name; ->引用成员变量和引用普通变量是一样的,有左值,也有右值 p->num = 20; int b = p->num;
初始化结构体方法
定义结构体变量时就赋初值 结构体的初始化就要使用{} //日期 struct date { int y,m,d; }; struct student { int num; char name[32]; strcut date birthday; float score; }; (1)、按定义时的顺序依次初始化各成员变量,用逗号分开; struct student s = { 1, "zhoushuaige", {1999,01,03}, 100 }; (2)、不按顺序,.成员变量名 = 值; struct student s = { .name = "zhangsan", .birthday = {2000,01,03}, }; (3)、结构体数组的初始化 a、按照数组元素的顺序依次初始化 struct student class[3] = { //class[0] { .num = 1, .name = "lisi", .birthday = {2000,01,03}, .score = 90 }, //class[1] { .num = 2, .name = "wangwu", .birthday = {2001,01,03}, .score = 86 }, //class[2] {} }; b、不按数组元素的顺序,[下标] = 这种方式不同的编译器,情况或者限制都会不一样 struct student class[3] = { [0] = { //class[0] .num = 1, .name = "lisi", .birthday = {2000,01,03}, .score = 90 }, [2] = { .num = 2, .name = "wangwu", .birthday = {2001,01,03}, .score = 86 }, };共用体
union 共用体名 { 成员类型1 成员变量1; 成员类型2 成员变量2; ....... 成员类型n 成员变量n; }; 共用体与结构体最大的区别: 结构体所占的内存大小是各成员变量之和; 共用体所占的内存大小是各成员变量中最大的那个。 共用体的存储空间是各成员之间共用的。 同一个时刻只能用一个成员变量,为了节省 内存 才提出的 共用体 。 例子: (1)、 union test { int a; int b; }; union test 占4个字节,成员变量a和b共用这四个字节 union test t; printf("%p\n",&t); printf("%p\n",&t.a); printf("%p\n",&t.b); t.a = 5; printf("%d\n",t.b); (2)、 union test { char a; int b; }; sizeof(union test) == 占4个字节 ?? union test t; printf("%p\n",&t); printf("%p\n",&t.a); printf("%p\n",&t.b); t.a = 65; printf("%c\n",t.a); 大端模式 与 小端模式 CPU 内部寄存器 是 按bit位 来存储信息的, 但是 CPU内部寄存器的数量 是 非常有限的,所以 我们经常需要把寄存器存储到 存储器(内存)当中去。 但是内存不是按 bit 来寻址的,按照字节编号(地址)来寻址 如果把寄存器的内容存储到内存当中去,那么 内存的低地址到底是存在寄存器中的低字节还是高字节呢?? 大端模式: 存储器的低地址,存放寄存器的高字节。 小端模式(小弟弟): 存储器的低地址,存放寄存器的低字节。练习: 1、你写一个代码,来验证一下 运行你代码的机器到底是小端模式还是大端模式??? union test { char a; int b; };
union test s; s.b = 1; if(s.a) { 小端 } else { 大端 } (3)、假设在32bit的小端模式的机器下运行,如下代码,请分析输出结果 union test { char a; int b; }; union test t; t.b = 255; t.b++; printf("%d\n",t.a);枚举
把该类型变量所有的可能的值一一列举出来。 所以枚举类型一定可以列举的值,也就是说整数值 有些一些情况,一个变量的值,是在一定范围之内的 如: int weekday; //星期几 //1 2 3 4 5 6 7 weekday = 1; weekday = 250; 枚举语法: enum weekday { MON = 1024, TUE, WUE, THU, FRI, SAT = 2048, SUN }; enum weekday w = MON;构造类型: 结构体 共用体 枚举 数组 也是一个构造类型 int a[4]; //定义一个数组 //同时你也声明了一个新的类型, 像a这样子的类型
定义一个与a类型一样的变量b typeof(a) b;typedef
typedef 是用来声明一个新的类型的 用来声明一个新的类型名,来替换一个已经拥有的类型。 方便移植 语法: typedef 现有的类型名 新类型名 =====> 新的类型名 就和 现有的类型名 类型一样 typedef unsigned char uchar8; uchar8 a; typedef unsigned int uint32; uint32 b; typedef struct student STU; STU s; ====> struct student s; int NUM[100]; //定义了一个数组,名为NUM 假如让你定义一个和NUM一样的类型变量a typeof(NUM) a; typedef int[100] NUM_T; NUM_T a; void (*p)(int , float); // p是什么呢?? //p是一个函数指针变量 typedef void (*p)(int , float) ; //p是什么?? //p是一个类型,函数指针类型 //指向 返回void , 带 int,float的函数字节对齐的问题
CPU 底层为了访问的效率出发,一般会要求,任何对象的地址是对齐。 自然对齐: 数据地址是数据长度的倍数。 如: sizeof(int) = 4; int a; &a 不是4的倍数,a就不是自然对齐 n字节对齐 地址是n的倍数(n一般是2的x次幂) 4 - 字节对齐 8 - 字节对齐 。。。。。 结构体的每一个成员变量通常会有一个默认的对齐方式,成员变量 将按照(除非程序员有其他的对齐要求)默认的对齐方式是:自然对齐 struct test { char a; //a的地址必须是1的倍数 int b; //b的地址必须是4的倍数 }; sizeof(struct test) == 8 a _ _ _ x x x x 在 32 bits x86 机器,编译: VC++ C++ builder DMC gcc 对 a char(1) 一字节对齐 a int (4) 四字节对齐 a short (2) 两字节对齐 a double (8) 8字节对齐 on windows 四字节对齐 on linux (除非 -malign-double 8字节对齐) a float (4) 4字节对齐 a long (4) 4字节对齐 a long long(8字节) 4字节对齐 a long double(10字节) (具体对齐方式和你的 电脑 还有 编译器 还有 系统 有关) any pointer (四字节) 4字节对齐 (任何指针) 对结构体按最大的原始类型的对齐方式 struct test { char a; //1 short b; //2 int c; //4 }; struct test { char a; //1 int c; //4 short b; //2 }; 对齐的方式,就会决定结构体是否会有空洞!!练习
1、 struct MaxedDate { char Data1; short Date2; int Date3; char Date4; }; sizeof(struct MAxedDate) === 12 2、 struct FindPad { float x; char n[1]; }; sizeof(struct FindPad) == 8 3、 struct FindPadshort { short x; char n[3]; }; sizeof(struct FindPadshort) == 6 4、 struct MixedDate { char data1; short data2; int data3; char date4 }; struct test { char s; struct MixedDate m; } sizeof(struct test) == 16