九、关键字
0x00 常见关键字
📚 C语言提供的关键字:
1. C语言提供的,不能自己创建关键字
2. 关键字不能做变量名
这里我们来简单地介绍几个:
💬 auto - 自动的
int main() { { int a = 10; //自动创建,自动销毁的 - 自动变量 // auto省略掉了 auto int a = 10; // auto新的C语言中也有其它用法 - 暂时不考虑 } return 0; }
💬 register - 寄存关键字
int main() { // 大量/频繁使用的数据,想放在寄存器中,提升效率 register int num = 100; //建议num的值存放在寄存器中 //是不是最终放到寄存器中是编译器说的算 // 其实现在编辑器已经很聪明了, // 就算你不主动加register,它也会帮你存到寄存器中。 return 0; }
💬 typedef - 类型重命名
// 这种罗里吧嗦的变量我们可以把它重命名一下 typedef unsigned int u_int; int main() { unsigned int num = 100; u_int num2 = 100; //和上面是等价的 return 0; }
📚 static - 静态的
1. static修饰局部变量
2. static修饰全局变量
3. static修饰函数
💬 static修饰局部变量
函数中局部变量:
声明周期延长:该变量不随函数结束而结束
初始化:只在第一次调用该函数时进行初始化
记忆性:后序调用时,该变量使用前一次函数调用完成之后保存的值
存储位置:不会存储在栈上,放在数据段
void test() { static int a = 1; //不销毁,生命周期变长了 a++; printf("%d ", a); } int main() { int i = 0; while(i<10) { test(); i++; } return 0; }
🚩 运行结果: 2 3 4 5 6 7 8 9 10 11
💬 static修饰全局变量
改变该变量的链接属性,让该变量具有文件作用域,即只能在当前文件中使用。
① Global.c:
static int g_val = 2021; // static 修饰全局变量, // 使得这个全局变量只能在自己所在的源文件(.c)内部可以使用 // 其他的源文件不能使用! // 全局变量,在其他原文件内部可以被使用,是因为全局变量具有外部链接属性 // 但是被static修饰之后,就变成了内部链接属性, // 其他的源文件就不能链接到这个静态的全局变量了!
② test.c:
extern int g_val; int main() { printf("%d\n", g_val); return 0; }
🚩 运行结果: test.obj : error LNK2001: 无法解析的外部符号 _g_val
💬 static修饰函数
改变该函数的链接属性,让该函数具有文件作用域,即只能在当前文件中使用。
① Add.c:
//static修饰函数, static int Add(int x, int y) { return x + y; }
💬 test1.c:
extern int Add(int, int); //声明外部函数 int main() { int a = 10; int b = 20; int sum = Add(a, b); printf("sum = %d\n", sum); return 0; }
🚩 运行结果:
test.obj : error LNK2019: 无法解析的外部符号 _Add,该符号在函数 _main 中被引用
0x01 define
📚 define 是一个预处理指令:
1. define 定义标识符常量
2. define 定义宏
💬 define 定义标识符常量:
#define MAX 1000 int main() { printf("%d\n", MAX); return 0; }
💬 define 定义宏:
#define ADD(X, Y) X+Y #define ADD1(X, Y) ((X)+(Y)) int main() { printf("%d\n", 4*ADD(2, 3)); // 4*2+3 = 11 printf("%d\n", 4*ADD1(2, 3)); // 4*(2+3) = 20 return 0; }
十、指针初探
0x00 指针介绍
❓ 什么是指针?
指针就是地址,地址就是指针。
指针,是C语言中的一个重要概念及其特点,也是掌握C语言比较困难的部分。指针也就是内存地址,指针变量是用来存放内存地址的变量,不同类型的指针变量所占用的存储单元长度是相同的,而存放数据的变量因数据的类型不同,所占用的存储空间长度也不同。有了指针以后,不仅可以对数据本身,也可以对存储数据的变量地址进行操作。
💬 变量都有地址,取出变量的地址如下:
int main() { int a = 10; // a在内存中要分配空间 - 4个字节 &a; // 取出num的地址 printf("%p\n", &a); //%p - 以地址的形式打印 return 0; }
🚩 打印出来的是a的地址
💬 定义指针变量,存储地址
* 说明 pa 是指针变量
int 说明 pa 执行的对象是 int 类型的
int main() { int a = 10; int* pa = &a; // pa是用来存放地址的,在C语言中叫pa的是指针变量 char ch = 'w'; char* pc = &ch; return 0; }
0x01 解引用操作
如果把定义指针理解为包装成快递,那么“解引用操作”就可以理解为是拆包裹
拆出来的值就是那个变量的值,甚至还可以通过“解引用”来修改它的值。
💬 解引用操作用法:
int main() { int a = 10; int* pa = &a; *pa = 20; // * 解引用操作 *pa就是通过pa里边的地址,找到a printf("%d\n", a); //20 return 0; }
0x02 指针的大小
📚 指针的大小
“指针的大小是相同的”
❓ 为什么相同?
“因为指针是用来存放地址的,指针需要多大空间,取决于地址的存储需要多大空间”
📺 指针是一种复合数据类型,指针变量内容是一个地址,因此一个指针可以表示该系统的整个地址集合,故按照32位编译代码,指针占4个字节,按照64位编译代码,指针占8个字节(注意:不是64位系统一定占8个字节,关键是要按照64位方式编译)。
32位 - 32bit - 4byte
64位 - 64bit - 8byte
💬 sizeof 计算指针的大小:
int main() { printf("%d\n", sizeof(char*)); printf("%d\n", sizeof(short*)); printf("%d\n", sizeof(int*)); printf("%d\n", sizeof(long*)); printf("%d\n", sizeof(long long*)); printf("%d\n", sizeof(float*)); printf("%d\n", sizeof(double*)); return 0; }
32位下都是 4 64位下都是 8
十一、结构体
0x00 什么是结构体
📚 结构体可以让C语言创建出新的类型
“结构体是C语言中特别重要的知识点,结构体使得C语言有能力描述复杂的类型”
💬 使用结构体描述学生 / 描述书:
// 创建一个学生的类型 struct Stu { char name[20]; // 姓名 int age; // 年龄 double score; // 分数 }; // ← 不要忘了加分号 // 创建一个书的类型 struct Book { char name[20]; float price; char id[30]; };
💬 结构体的初始化:
点操作符和箭头操作符
. 结构体变量.成员
-> 结构体指针->成员
struct Stu { char name[20]; // 姓名 int age; // 年龄 double score; // 分数 }; struct Book { char name[20]; float price; char id[30]; }; int main() { struct Stu s = {"张三", 20, 85.5}; // 结构体的创建和初始化 // 点操作符 printf("1: %s %d %lf\n", s.name, s.age, s.score); struct Stu* ps = &s; printf("2: %s %d %lf\n", (*ps).name, (*ps).age, (*ps).score); // ❎ 可以但不推荐 // 箭头操作符 printf("3: %s %d %lf\n", ps->name, ps->age, ps->score); // ✅ 推荐 return 0; }