结构体和共同体
-
结构体,有点像java的类:struct 结构体名{成员列表}
1
2
3
4
5
6
7
8
9struct Man{
int age;
int sex;
};
或者:
struct Man{
int age;
int sex;
}man; -
使用结构体的成员变量时使用结构体名.成员名
-
初始化结构体时可以直接加括号;也可以直接定义结构体数组初始化结构体数组:;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21man[]={{…},{…}}
struct Man{
int age;
int sex;
}man={2,4};
或者是:
struct Man{
int age;
int sex;
}
函数中:
struct Man man={2,4};
或者是:
structMan{
int age;
int sex;
}man[3];
struct Man man[3];
man={{},{},{}}; -
结构体指针:结构体类型 *指针名,使用其成员时:(*pMan).age(一定要括起来),还有一种方法是pMan->成员名,同时结构体指针不能直接初始化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15struct Man{
int age;
int name;
}m={10,89};
struct Man *man;
man=&m;
printf("%d\n",(*man).age
//或者是
printf("%d",man->age);
结果是:
10
10 -
结构体作为函数参数时,要使用关键字struct:void a(struct Man man)。传递结构体时需要传递的数据较大,所以可以传递结构体的指针代替void a(struct Man *man)
1
2
3
4
5
6
7
8int printMan(struct Man *m){
printf("%d",m->name);
return 0;
}
调用:
printMan(&m);
结果:89 -
*malloc(unsigned int size),在内存中动态分配一块size大小的内存空间,会返回一个指针,错误时返回NULL;*calloc(unsigned n,unsigned size),该函数是在内存中动态分配n个长度为size的连续内存数组;free(void*ptr)该函数由指针指向内存去,使部分内存区能被其他变量使用
1
2
3
4struct Man* man;
man=(struct Man*)malloc(sizeof(struct Man)); //申请Man大小的空间,再将该空间的指针强行转为 //struct Man*指针
free(man); //将man内存空间回收掉 -
共同体和结构体很像:union 共同体名{成员变量列表}变量列表;区别是结构体定义了多个数据组成的特殊类型,共同体是所有数据成员的共享的内存,所有共同体在同一时刻只能有一个值,属于某一个数据成员。所以共同体的内存大小为其成员中最大的内存大小
1
2
3
4
5
6
7
8union Page{
int p;
char *t[1];
};
printf("%d", sizeof(union Page));
结果:8 -
union Man{int age;char name};union Man man;man.age=12;那么man.name也是12(12的ascii码)(测试多种情况,如字符串);其初始化为:man={12};
1
2
3
4
5
6
7
8
9union Page{
int p;
char t[10];
char* m[10];
};
union Page page={13,19};
printf("%d,%d",*page.m,*page.t);
结果:13,13 -
枚举enum 例子如下:如果Red为1,Green就自动会加1。使用枚举直接使用Red
1
2
3
4
5
6
7
8
9
10enum Color(
Rad,
Green
);
enum Color(
Rad=1,
Green
)
printf("%d,%d",Rad,Green);
结果:1,2
位运算和宏定义
-
位运算:&与,|或,~取反,^按位异或(两个位相同为0,不同为1),<<左移,>>右移
-
循环位移,将数据左移,左边移除部分重新添加到右边(a>>(32-T))|(a<T)
-
位段是特殊的结构类型,其所有的成员的长度均已二进制位为单位定义的,结构中的成员称为位段:结构机构名{类型变量名:长度; 类型变量名2:长度;}。如下:位段必须是int、unsigned和signed中的一种
1
2
3
4struct status{
unsigned sign:1;
unsigned zero:2;
}flags; -
位段可以加入无名位段,使后面位段从后面空位置开始存储:unsigned :0;可以使用%d等输出位段
-
宏定义 #define 宏名数据(不需要分号);使用#undef TEST终止宏定义(测试终止后继续使用,停止后再次使用,编译会出问题,比如在另一个方法中停止,经过测试稍微复杂一点程序就不能直接识别可以运行);宏定义用于预处理,只做符号替换,不分配内存
1
2
3
4
5
6
7
8printf("%d",TAG);
#undef TAG;
printf("%d",TAG); //编译不通过
printf("%d\n",TAG);
undef();
printf("%d",TAG);
结果为1 1 -
带参数的宏定义:#define 名(参数表)字符串,使用时参数最好带括号,不然可能会错。如#define MIX(a,b)(a*b+b),使用时如果是MIX(1,2),则正确,如实MIX(1,1+2),则会这样算11+2+1+2,结果错误,所以最好是((a)(b)+(b)),同时调用时最好也加括号,如5MIX(1,2),会成为51*2+2,所以最好在最外面加括号
1
2
3
4
5
6#define MIX(a,b)(a*b+b)
printf("%d,%d",MIX(2,3),MIX(2+1,3));
结果为:
8,9 -
#include<>和#include””一样,引入的头文件一般是.h,一般会在该文件中放置宏定义、结构、联合、枚举、typedef声明、外部函数声明,全局变量声明
-
#if命令,含义是如果#if后面的表达式为真,则编译#if和#endif之间的代码,否则不编译:#if 表达式语句段 #endif,这个与if很像,#elif效果和else if一样,#else和else一样,最后都要#endif结尾
-
#ifdef,判断宏定义常量是否被定义,@ifdef 宏名语句段 #endif,其他用法与#if一样;#ifndef作用与#ifdef相反,用法一样
-
预宏定义名:__LINE__ 当前被编译的代码的行号;__FILE__当前源文件的名称;__DATA__当前源文件的创建日期; __TIME__ 当前源文件的创建时间;__STDC__判断当前编译器是否是标准C,若是1则是,否则不是
-
#line:改变行号和文件名 #line行号/文件名,该文件中输出行号和文件名会改变;#pragma:指定编译器状态 @pragma 参数,有一下几个参数:message:在输出窗口中输出信息;code_seg:设置程序中函数代码存放的代码段;once:保证头文件被编译一次
1 | #line 12 "main.c"; //代表该行下面那行行号是12 |