第三天
1. 常见关键字
typedef
类型定义
- 利用typedef封装名称可以减少部分define定义带来的错误
- 与class, sturct union, enum声明不同, typedef==不会引入新类型== -只是引入现有类型的新名称
作用:
- 定义一种类型的别名,这种定义不是简单的替换,而是封装
#include <stdio.h>
typedef char* PCHAR;
int main() {
PCHAR p1, p2;
// char *p1,p2;这样只是定义了一个char*指针和一个char字符变量。
return 0;
}
- 同样是定义别名,还可以用来定义与平台无关的类型。
当跨平台时,只要改下 typedef 本身就行,不用对其他源码做任何修改。
- 给结构体起别名
#include <stdio.h>
typedef struct STUDENT {
char *name;
int age;
int sex;
}STU;
int main() {
STU stu;
return 0;
}
register
- 用register声明的变量是寄存器变量,是存放在==CPU的寄存器==里的
平时声明的变量是存放在==内存==中.
- 寄存器变量和普通变量比起来==速度==上的差异很大
- 寄存器有这么两个特点,一个是运算速度快,一个是==不能取地址==。
==给变量加上register关键字,仅仅是建议放到寄存器中,最终是否执行取决于编译器==
现在的C编译环境能比程序员做出更好的决定;
register int num=0;
signed 和 unsigned
int a;//默认有符号
signed int b;//有符号
unsigned int c ;//无符号
struct结构体
结构体(struct)是复合数据类型的一种,*注意:在C语言中,==结构体不能包含函数==。*
struct 结构体名(也就是可选标记名)
{
成员变量;
};//使用分号表示定义结束;
#include <stdio.h>
//声明一个结构体
struct MYSTRUCT
{
char a;
int b;
float c;
char* d;
};//注意分号不能少
int main() {
struct MYSTRUCT m1= { 'a',10,3.14,"struct"};
printf("%s",m1.d);
return 0;
}
定义应该在初始化之前,否则会报错!
在函数外部定义的结构体,在其声明后的所有函数都可以使用。
- 初始化:
//对结构体初始化
struct book s1={
"guojiajiaoyun",//author为字符数组
"yuwen",//title为字符串
22.5
};
//在定义变量之后,若再要对变量的成员赋值,那么只能单个赋值了;
struct book s1;
s1={
"guojiajiaoyun",//author为字符数组
"yuwen",//title为字符串
22.5
};//这样就是不行的,只能在定义的时候初始化才能全部赋值,之后就不能再全体赋值了;
// 只能单个赋值
s1.title = "yuwen";........//单个赋值;
这种赋值方法就可以不按顺序:
int main() {
struct MYSTRUCT m1 = {
.b = 10,
.a = 'a',
.d = "struct",
.c = 3.14
};
printf("%s",m1.d);
return 0;
}
union:联合体或共用体
定义格式:
union 共用体名{
成员列表
};
==结构体和共用体的区别==在于:
-
结构体的各个成员会占用不同的内存,互相之间没有影响;而共用体的所有成员占用同一段内存,==修改一个成员会影响其余所有成员==。
- 结构体占用的内存==大于等于==所有成员占用的内存的总和(成员之间可能会存在缝隙),共用体占用的内存==等于最长==的成员占用的内存。
#include <stdio.h>
//声明
union MyUnion
{
int a;
char b;
double c;
char* d;
};
int main() {
union MyUnion m ;//创建变量
m.a = 10;
printf("%d\n", m.a);
m.b = 'b';
printf("%c\n", m.b);
m.c = 3.12;
printf("%f \n", m.c);
m.d = "union";
printf("%s\n",m.d);
return 0;
}
- 修改一个成员会影响其余所有成员:
static静态变量
作用:
- ==隐藏==:
全局变量或者函数,可以通过extern访问其余文件的变量。如果加了static,就会对其余源文件隐藏。
利用这一特性可以在不同文件中定义同名的变量或者函数。
- 保持变量内容的==持久==
存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。
共有两种变量存储在静态存储区:全局变量和 static 变量,
- static 的第三个作用是==默认初始化为 0==
在静态数据区,内存中所有的字节默认值都是 0x00,某些时候这一特点可以减少程序员的工作量。
- static修饰的局部变量: 生命周期变长
- static修饰的全局变量:让全局变量只能在自己所在的源文件内部使用
volatile
声明一个变量为volatile,可以在数据类型之前或之后加上关键字volatile。
它告诉编译器该==变量值可能随时发生变化==,且这种变化并==不是代码引起==的
volatile int a;
int volatile b;
只要变量可能被意外的修改,就需要把该变量声明为volatile。
在实际应用中,只有三种类型数据可能被修改:
//1.外设寄存器地址映射
//2.在中断服务程序中修改全局变量
//3.在多线程、多任务应用中,全局变量被多个任务读写
auto自动存储类型
auto自动存储类型,代码块中的变量缺省情况下就是这种类型.
存放于==堆栈==中,只有程序执行这些代码块时这种自动变量才会被创建.代码块执行结束后自动变量便被释放.
int main()
{
int num=2;
for(int i=0;i<3;i++){
printf("num=%d\n",num);
num++;
{
auto int num=1;
printf("auto_num=%d\n",num);
num++;
}
}
}
2. define
C 语言中,除了可以用 #define 定义一个标识符来表示一个常量,还可以用 #define 定义函数
//定义常量
#define A 100 //定义整型变量A值为100
#define B "Hello" //定义字符串变量B值为"Hello"(定义字符串需要加双引号)
#define C 3.1415926 //定义浮点数变量C值为3.1415926
//定义函数
#define MAX(a,b) (a>b)?a:b //取两个数最大值
#define MIN(a,b) (a<b)?a:b //取两个数最小值
#define A (x*2+5)
凡是以 # 开头的均为预处理指令,预处理又叫预编译。预编译不是编译,而是编译前的处理。这个操作是在正式编译之前由系统自动完成的。
3.指针
每一个变量都有一个内存位置,每一个内存位置都定义了可使用 & 运算符访问的地址,它表示了在内存中的一个地址。
#include <stdio.h>
int main() {
int var = 100;//定义一个整型变量
int* p;//定义一个指向整型变量的指针
p = &var;//指针p指向var的地址
printf("%p\n",&var);//var的地址
printf("%p\n",p);//指针p指向的地址
printf("%d\n",var);//var的存储的内容
printf("%d\n",*p);//指针p指向的内容
return 0;
}
什么是指针?
指针也就是内存地址,指针变量是用来存放内存地址的变量。
指针变量声明的一般形式为:
type *var_name;
不同数据类型的指针之间唯一的不同是,指针所指向的变量或常量的数据类型不同。
NULL指针
在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯。==赋为 NULL 值的指针==被称为空指针。
int* p2 = NULL;
printf("%p\n", p2);//指针p指向的地址