一、函数指针二、回调函数
练习:编写函数,定义一个无符号4字节的整数,然后获取每一个字节的内容,然后返回相加之和面试题:define和typedef的区别? 三、存储类型四、内存管理
思考题1 思考题2五、结构体
5.1 结构体的使用
5.1.1 结构体的定义和赋值5.1.2 定义结构体同时赋值5.1.3 结构体数组 5.2 结构体定义的方式
5.2.1 无名结构体5.2.2 有名结构体5.2.3 struct的特殊赋值方式 5.3 结构体占用字节大小
5.3.1 结构体的位域 六、共用体
6.1 基本用法6.2 大小端的判断6.3结构体中定义联合体 七、枚举类型
练习:
实例一:实例二
一、函数指针函数指针:本质是一个指针,指向一个函数;
我们定义的函数名其实就是一个指针,保存当前函数代码区的首地址;
函数指针学习的目的就是想解决能不能定义一个指针,可以像函数名一样对当前函数进行调用。
函数指针定义的格式:
返回值类型(*变量名)(参数);
函数数值真的作用:将一个函数作为参数传递给另一个函数是需要定义成函数指针,也称之为回调函数
#include二、回调函数typedef unsigned char uchar; //用uchar表示 unsigned char typedef int (*T)(int,int); //声明T为函数指针类型 void f1() { printf("hello world!n"); } int f2(int x,int y) { printf("this is f2n"); return 0; } int main(int argc, const char *argv[]) { void (*p1)(); //定义函数指针 p1 = f1;//不能写成p1 = f1(); ---->调用f1函数,将返回值赋值给p1 p1(); // p1 = f2; //类型不兼容 int (*p2)(int,int); p2 = f2; p2(1,2); T p3; //等价于int(*p3)(int,int) p3 = f2; p3(1,2); return 0; }
#include练习:编写函数,定义一个无符号4字节的整数,然后获取每一个字节的内容,然后返回相加之和int less(int x,int y) { return (x < y) ? 1 : 0; } int greater(int x,int y) { return (x > y) ? 1 : 0; } void Sort(int a[],int length,int (*p)(int,int)) { int i,j; for(i = 0 ; i < length - 1;i++) { for(j = 0 ; j < length - 1 - i;j++) { if(p(a[j],a[j+1])) { #if 0 int t = a[j]; a[j] = a[j+1]; a[j+1] = t; #endif a[j] = a[j] + a[j + 1]; a[j + 1] = a[j] - a[j + 1]; a[j] = a[j] - a[j + 1]; } } } } void Print(int a[],int length) { int i; for(i = 0 ; i < length;i++) { printf("%d ",a[i]); } putchar(10); } int main(int argc, const char *argv[]) { int a[10] = {0}; printf("请输入10个数字:n"); int i; int length = sizeof(a)/sizeof(a[0]); for(i = 0 ; i < length;i++) { scanf("%d",&a[i]); } Sort(a,length,less); Print(a,length); return 0; }
要求:这个整数需要传参,返回每一个字节之和
458963212 —>0001 1011 0101 1011 0011 1001 0000 1100
0000 1100 —>12
0011 1001 —> 57
0101 1011 —>91
0001 1011 —> 27
12+57+91+27 = 187
#include面试题:define和typedef的区别?int GetByteSum(unsigned int num) { int sum = 0; #if 0 //将每8位拿出来 int byte1,byte2,byte3,byte4; byte1 = num & 0xff; byte2 = (num >> 8) & 0xff; byte3 = (num >> 16) & 0xff; byte4 = (num >> 24) & 0xff; sum = byte1 + byte2 + byte3 + byte4; #endif unsigned char *p = (unsigned char)# int i; for(i = 0 ; i < 4; i++) { sum += *p; p++; } p = NULL; return sum; } int main(int argc, const char *argv[]) { unsigned int num = 458963212; int n = GetByteSum(num); printf("n = %dn",n); return 0; }
1.#define是一个预处理指令,在预处理阶段进行字符串的简单替换,并不参与到编译阶段,typedef是类型的重定义,在编译的时候进行过类型的重定义;
2.当使用#define和typedef定义多个指针的时候,define定义的是第一个指针,后面全是变量,而typedef定义的全是指针;
3.define一般用于表示常量,还有函数的替换工作,typedef用于类型重定义。
#include三、存储类型#include // 方法1:({}) // 方法2:do{}while(0) int min; #define MAX(a,b) ({int max;if(a > b)max=a;else max=b;max;}) //({})里面可以有多条语句,最后一句就是宏的返回值 #define MIN(a,b) do{if(a < b) min = a;else min = b;}while(0) #define PRINT_MSG(msg) do{printf("%sn",msg);return -1;}while(0) #define S(n) #n //#代表字符串化 int main(int argc, const char *argv[]) { int *p = NULL; int hello = 100; printf("max = %dn",MAX(100,200)); MIN(100,200); printf("min = %dn",min); p = (int *)malloc(4); if(p == NULL) { PRINT_MSG("malloc failed!n"); } printf("%sn",S(10)); //字符串化 return 0; }
auto:
register:定义变量在寄存器上,运行速率快,但是芯片的寄存器的个数有限制,不能无限使用;寄存器变量不能取地址;
extern: 使用的变量或者文件在其它文件中定义;
static:
1.限定作用域:(修饰的变量或者函数只能在本文件中使用)
2.延长生命周期
volatile:保证数据每次都从内存中取值,而不从缓存中取数据,防止编译器对代码进行优化
1.多线程访问同一个变量的时候
2.使用C语言 *** 作硬件地址的时候
#include四、内存管理int a = 100; void fun() { static int i = 0; printf("i = %dn",i++); printf("a = %dn",a); } int main(int argc, const char *argv[]) { int a = 200; printf("a = %dn",a); { int a = 300; printf("a = %dn",a); } printf("i = %dn",i); fun(); fun(); fun(); return 0; }
---------------------------- 栈区:局部变量,正在调用的函数,形参都在栈 栈区由于在释放时不会清0,所以在定义变量的时候不初始化,他们都是随机值, 栈区空间由系统自动申请,自动释放 ---------------------------- 堆区:使用malloc分配的内存都在堆区,手动申请,手动释放 ---------------------------- 静态区|.bss:使用static修饰的未初始化的变量和全局的未初始化的变量在.bss段 |---------------------------- |.data:使用static修饰的已初始化的变量和全局的已初始化的变量在.data段 |---------------------------- |.text:代码段,文本段 |---------------------------- |.ro: 只读数据段 |const int a; |char *p = "helloworld"; #include思考题1int a; //.bss段 static int w = 4; //.data int b = 1234; //.data const int g = 789; //.ro void func(void) { const int y = 1234; //.ro int *p = &y; //栈区 } int main(int argc, const char *argv[]) { char ch; //.stack char ch1 = 'a'; //.stack char *p = "aaaa"; //P .stack "aaaa":.ro return 0; }
#include思考题2int main(int argc, const char *argv[]) { char *p = NULL; char *tmp = "helloworld"; p = (tmp + 4); //p[-1] = ? p[-5] = ? printf("p[-1] = %c,p[-5] = %cn",p[-1],p[-5]); return 0; }
#include五、结构体#include int main(int argc, const char *argv[]) { char *data = "12345678"; short *tmp = NULL; char p[6] = {0}; tmp = (short *)&p[2]; *tmp = atoi(&data[4]); printf("*tmp = %dn",*tmp); //p[0],p[1],p[2],p[3],p[4],p[5]? int i = 0 ; for(i = 0 ; i < 5;i++) { printf("p[%d] = %#xn",i,p[i]); } return 0; } jsetc@linux:~/jsetc/208/day6$ ./8-思考题2 *tmp = 5678 p[0] = 0 p[1] = 0 p[2] = 0x2e p[3] = 0x16 p[4] = 0
结构体是一个构造类型,结构体的成员在内存上是连续的,
但是结构体的成员的类型可以是不相同的。
结构体的关键词用struct来标注。
格式:
struct 类型名{ 成员1; 成员2; 。。。 };
【注意事项】
(1)结构体使用struct来标识
(2)struct后面跟的是结构体的类型名,而非变量名
(3)结构体的成员是被{}所包括着
(4){}后面要加;
(5)结构体的成员可以不尽相同
(6)结构体成员之间用分号隔开
(7)定义结构体的时候不能赋值
(8)在结构体里面不能写函数,因为函数占用的字节不固定,但是可以写函数指针
(9)结构体访问成员的方式 “变量.成员”
(10) 结构体指针访问成员的方式“变量->成员”
#include5.1.2 定义结构体同时赋值struct person{ char name[32]; char sex; int age; int high; float weight; }; int main(int argc, const char *argv[]) { struct person p1; strcpy(p1.name,"张三"); p1.sex = 'm'; p1.age = 18; p1.high = 189; p1.weight = 80; struct person *p2 = NULL; p2 = (struct person *)malloc(sizeof(*p2)); if(p2 == NULL) { printf("malloc failure"); } strcpy(p2->name,"张三"); p2->sex = 'm'; p2->age = 18; p2->high = 189; p2->weight = 80; return 0; }
#include5.1.3 结构体数组struct person{ char name[32]; char sex; int age; int high; float weight; }; int main(int argc, const char *argv[]) { struct person p1 = {"zhangsan",'m',20,186,80}; //给所有成员初始化 struct person p2 = { //选择成员初始化 .name = "zhangsan", .weight = 80 }; return 0; }
struct person p1[3]; //这个就是结构体数组,数组中有三个strcut person
5.2 结构体定义的方式 5.2.1 无名结构体struct{ char name[32]; int age; float weight; }变量1,变量2; struct 变量1;----->这个是错误的写法 typedef struct{ char name[32]; int age; float weight; }student_t; //类型名 student_t 变量1,变量2;
【注意】结构体可以整体赋值,数组在定义后不允许整体赋值
5.2.2 有名结构体typedef struct student{ char name[32]; int age; float weight; }student_t; //类型名 student_t 变量1,变量2;5.2.3 struct的特殊赋值方式
#include5.3 结构体占用字节大小#include #include typedef struct person{ char name[32]; char sex; int age; int high; float weight; }person; int main(int argc, const char *argv[]) { person p; p = (person){"张安",'m',20,189,80}; printf("name = %s,sex = %c age = %d high = %d weight = %fn",p.name,p.sex,p.age,p.high,p.weight); //结构体数组赋值 //方法1 person p1[2] = { { .name = "zhangsan", .age = 19 }, { .name = "zhangsi", .age = 20 } }; //方法2: person p2[3] = { [0] = { .name = "zhangsan", .age = 19 }, [2] = { .name = "zhangsi", .age = 20 } }; return 0; } //方法3: person p3[3]; p3[0].name
规则:
结构体占用字节大小的口诀是:
1.如果结构体内部的变量类型最大成员小于等于4字节,就按照最大的类型进行内存对齐
2.如果结构体内部变量类型大于四字节,就按照四字节对齐
3.结构体最终大小和结构体中成员最大类型对齐(32位和4字节对齐,64位和8字节对齐)
#include5.3.1 结构体的位域struct aa{ char a; //1个字节 }; struct bb{ short a; //2个字节 }; struct cc{ int a; //4个字节 }; struct dd{ char a; // 2个字节 char b; }; struct ee{ int a; // 8个字节 char b; }; struct ff{ char a; // 6个字节 short b; char c; }; struct gg{ char a; // 8个字节 short b; int c; }; struct hh{ short a; // 8个字节 char b; int c; }; struct ii{ char a[3]; // 12个字节 int b; char c; short d; }; struct jj{ double a; // 24个字节 char b; int c; short d; float e; }; int main(int argc, const char *argv[]) { struct ff a; struct gg b; struct jj c; struct ii d; printf("aa = %ldn",sizeof(struct aa)); printf("bb = %ldn",sizeof(struct bb)); printf("cc = %ldn",sizeof(struct cc)); printf("dd = %ldn",sizeof(struct dd)); printf("ee = %ldn",sizeof(struct ee)); printf("ff = %ldn",sizeof(struct ff)); printf("gg = %ldn",sizeof(struct gg)); printf("hh = %ldn",sizeof(struct hh)); printf("ii = %ldn",sizeof(struct ii)); printf("jj = %ldn",sizeof(struct jj)); printf("ff.a = %pnff.b = %pnff.c = %pn",&a.a,&a.b,&a.c); printf("gg.a = %pngg.b = %pngg.c = %pn",&b.a,&b.b,&b.c); printf("jj.a = %pnjj.b = %pnjj.c = %pnjj.d = %pnjj.e = %pnn",&c.a,&c.b,&c.c,&c.d,&c.e); printf("ii.a = %pnii.b = %pnii.c = %pnii.d = %pn",d.a,&d.b,&d.c,&d.d); return 0; }
压缩结构体大小的一种方式
#includestruct aa{ char a:1; char b:5; char c:3; }; int main(int argc, const char *argv[]) { printf("sizeof(aa) = %ldn",sizeof(struct aa)); return 0; }
【注意】
1.在结构体内部进行位域 *** 作的时候,是从内存最低位置开始站位,如果这个变量是有
符号的,那么它的最高位就是符号位,如果这个位域只有一位,它既是符号位又是数据位
2.结构体位域的成员不能够取地址
union内部的成员公用同一块内存空间,共用体的大小就是内部最大成员的内存空间
不管union有多少个成员,union的内存空间都是这个最大成员的内存空间
格式:
union 类型名{ char a; short b; int c; };6.2 大小端的判断
字节序:
大端序:高字节存放在低地址,低字节存放在高地址(网络序)
小端序:高字节存放在高地址,低字节存放在低地址
#include6.3结构体中定义联合体typedef union aa{ unsigned char a; int c; }aa_t; int main(int argc, const char *argv[]) { aa_t a; a.c = 0x12345678; if(a.a == 0x12) { printf("这是大端机器n"); } else if(a.a == 0x78) { printf("这是小端机器n"); } return 0; }
作用:让结构体的通用性更强
#include七、枚举类型struct aa { char a; union{ int b; char c; }; }; int main(int argc, const char *argv[]) { struct aa a; a.a = 10; a.b = 0xaabb; printf("size = %ldn",sizeof(a)); printf("c = %#xn",a.c); return 0; }
枚举就是有限数据的罗列,比如一周有七天,一年有12个月,
这些都是有限的罗列,适合用枚举
格式:
enum 类型名{ 成员1, 成员2, 成员3, 成员4 = 10, 成员5, .。。 成员n, };
【注意】
(1)枚举类型的关键是enum
(2)枚举的成员没有变量类型
(3)成员间通过逗号来区分
(4)枚举的成员的值依次向下递增1
(5)枚举中的成员访问不是通过.或者->来访问,直接拿成员使用
(6)枚举类型的大小是4个字节
(7)枚举类型如果不赋初值,默认从0开始
#include实例二enum week{ MON = 1, TUS, WED, THU, FRI, SAT, SUN }; int main(int argc, const char *argv[]) { enum week day; printf("day size = %ldn",sizeof(day)); day = TUS; printf("day = %dn",day); day = 10; //虽然编译器不会报错,但是不能这样赋值 //给枚举类型变量赋值的时候,只能赋值枚举常量 printf("day = %dn",day); return 0; }
#include#define S(n) case n: return #n typedef enum leds{ RED, GREEN, BLUE, }leds; char *led_type_to_str(enum leds led) { switch(led) { S(RED); S(GREEN); S(BLUE); default: return "不存在的"; } } leds led_open(leds led) { printf("打开%s灯n",led_type_to_str(led)); return led; } int main(int argc, const char *argv[]) { #if 0 char *p = NULL; enum leds led; led = led_open(RED); p = led_type_to_str(led); printf("打开%s-ok!n",p); #endif printf("打开%s-ok!n",led_type_to_str(led_open(RED))); return 0; }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)