Chapter2 C编程
1. 数据类型、变量
-
变量未初始化初值
C 语言中变量的默认值取决于其类型和作用域。
全局变量和静态变量的默认值为 0,
字符型变量的默认值为 \0,
指针变量的默认值为 NULL,
局部变量(在函数内部定义的非静态变量)不会自动初始化为默认值,它们的初始值是未定义的(包含垃圾值)。因此,在使用局部变量之前,应该显式地为其赋予一个初始值。
数据类型转化
隐式类型转换:隐式类型转换是在表达式中自动发生的,无需进行任何明确的指令或函数调用。它通常是将一种较小的类型自动转换为较大的类型,例如,将int类型转换为long类型或float类型转换为double类型。隐式类型转换也可能会导致数据精度丢失或数据截断。
显式类型转换:显式类型转换需要使用强制类型转换运算符(type casting operator),它可以将一个数据类型的值强制转换为另一种数据类型的值。强制类型转换可以使程序员在必要时对数据类型进行更精确的控制,但也可能会导致数据丢失或截断。
2. 运算符
三元运算符
(a>0)?b:c
判断是否表达式a>0是否为真,true取b,false取c
用于替代简单的if-else判断
3. C指针
定义指针
指针解址符—— *
指针取址符—— &
// 函数定义,通过指针修改原始变量的值
void change_value(int *ptr) {
*ptr = 20;
}
void main() {
int num = 10;
// 调用函数,传递变量num的地址
change_value(&num);
}
结构体指针
-
访问结构体成员
结构体变量用 . 来访问结构体的成员
-
访问结构体指针的结构体成员
指向结构体的结构体指针,要用->来访问指向的结构体成员
-
访问结构体指针的结构体成员,该结构体嵌套的内部结构体
一个指针指向结构体1,而结构体1成员有一个结构体2,通过该指针访问结构体2的成员
如:结构体1->结构体1内的结构体2
->结构体2的成员,第二个->换成.
函数指针与回调函数
-
函数指针:本质上是一个指针,但指向的是一个函数首地址(指针不能偏移),可以用函数指针来传递函数,常用于回调函数中
-
回调函数callback:通过函数指针实现的一种回调机制;即当某条件(事件)触发后,执行相对应登记(注册)的动作(函数)。
你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件。
// 事件类型枚举
typedef enum {
CLICK,
MIDDLE_CLICK,
RIGHT_CLICK,
KEY_PRESS,
KEY_RELEASE,
MOUSE_MOVE,
SCROLL,
}EventType;
// 事件结构体
typedef struct {
EventType type;
int x, y;
char key;
}Event;
// 定义回调函数类型
//EventCallback 函数指针数据类型,Event 函数变量
typedef void (*EventCallback)(const Event*);
// 事件处理器结构体
typedef struct {
EventCallback callbacks[10]; // 假设最多10种事件类型,对应最多10个处理函数
}EventHandler;
// 注册事件回调
void registerCallback(EventHandler* handler, EventType type, EventCallback callback) {
handler->callbacks[type] = callback; //函数指针赋值
}
// 事件分发器
void dispatchEvent(EventHandler* handler, const Event* event) {
if (handler->callbacks[event->type] != NULL) {
handler->callbacks[event->type](event);
}
}
// 点击事件处理函数
void onClickCallback(const Event* event) {
printf("点击事件触发了!坐标: (%d, %d)\n", event->x, event->y);
}
// 按键事件处理函数
void onKeyPressCallback(const Event* event) {
printf("按键事件触发了!按下的键是: %c\n", event->key);
}
void main() {
// 创建并初始化事件处理器
EventHandler handler = {NULL};
// 注册回调函数
registerCallback(&handler, CLICK, onClickCallback);
// 模拟点击事件
Event clickEvent = {CLICK, 100, 200};
// 事件触发
dispatchEvent(&handler, &clickEvent);
}
4. C函数
定义函数
函数由一个函数头和一个函数主体组成。
-
返回类型return_type:一个函数可以返回一个值。return_type 是函数返回的值的数据类型。有些函数执行所需的操作而不返回值,在这种情况下,return_type 是关键字 void。
-
函数名称function_name:这是函数的实际名称。函数名和参数列表一起构成了函数签名。
-
参数parameter:参数就像是占位符。当函数被调用时,您向参数传递一个值,这个值被称为实际参数。参数列表包括函数参数的类型、顺序、数量。参数是可选的,也就是说,函数可能不包含参数。
-
函数主体body:函数主体包含一组定义函数执行任务的语句。
指针函数
指针函数: 本质上是一个函数,函数的返回值是一个指针
//1 (void):这个函数不接收任何参数
//2 (*func_ptr):func_ptr 是一个指针
//3 void:这个函数没有返回值
//4 typedef:给前面这一整串起别名
// 1. 定义类型别名:func_ptr = 无参无返回值函数指针
typedef void (*func_ptr)(void);
// 2. 写一个匹配的函数
void my_func(void) {
// 无参、无返回值 ✔️
}
// 3. 使用这个类型定义指针变量
int main() {
func_ptr p; // 定义一个函数指针变量 p
p = my_func; // 把函数地址赋值给指针
p(); // 调用函数 → 等价 my_func()
}
5. C动态内存分配
void *calloc(int num, int size);
//在内存中动态地分配 num 个长度为 size 的连续空间,并将每一个字节都初始化为 0。
//所以它的结果是分配了 num*size 个字节长度的内存空间,并且每个字节的值都是 0。