C语言
C语言是一种通用的、过程式编程语言,广泛应用于系统编程和嵌入式系统开发。以下是C语言的一些基础知识:
1. 基本语法
1.1. Hello, World!
这是一个典型的“Hello, World!”程序,展示了C语言的基本结构:
#include <stdio.h>
int main() { printf("Hello, World!\n"); return 0;}
1.2. 注释
- 单行注释:使用
//
- 多行注释:使用
/* ... */
// 这是单行注释/*这是多行注释*/
2. 数据类型
C语言提供了多种数据类型,包括基本数据类型和用户自定义数据类型。
2.1. 基本数据类型
- 整数类型:
int
,short
,long
,long long
- 浮点类型:
float
,double
- 字符类型:
char
- 布尔类型:
_Bool
(在stdbool.h
中定义为bool
)
int a = 10;float b = 3.14;char c = 'A';
3. 变量和常量
3.1. 变量声明和初始化
int a = 5;float b = 4.5;char c = 'x';
3.2. 常量
使用 const
关键字定义常量,值不能被修改。
const int DAYS_IN_WEEK = 7;
4. 运算符
C语言支持多种运算符:
- 算术运算符:
+
,-
,*
,/
,%
- 关系运算符:
==
,!=
,>
,<
,>=
,<=
- 逻辑运算符:
&&
,||
,!
- 位运算符:
&
,|
,^
,~
,<<
,>>
- 赋值运算符:
=
,+=
,-=
,*=
,/=
,%=
等
5. 控制结构
5.1. 条件语句
if (a > b) { // 执行代码} else if (a == b) { // 执行代码} else { // 执行代码}
5.2. 循环语句
for
循环
for (int i = 0; i < 10; i++) { // 执行代码}
while
循环
int i = 0;while (i < 10) { // 执行代码 i++;}
do-while
循环
int i = 0;do { // 执行代码 i++;} while (i < 10);
6. 数组和指针
6.1. 数组
int numbers[5] = {1, 2, 3, 4, 5};
6.2. 指针
int a = 10;int *p = &a; // p 是指向 a 的指针
7. 函数
7.1. 函数定义和调用
#include <stdio.h>
int add(int x, int y) { return x + y;}
int main() { int sum = add(3, 5); printf("Sum: %d\n", sum); return 0;}
7.2. 函数声明
在函数定义之前进行声明,以便在其他函数中调用。
int add(int, int);
int main() { int sum = add(3, 5); return 0;}
int add(int x, int y) { return x + y;}
8. 结构体
结构体用于定义复杂数据类型。
struct Point { int x; int y;};
int main() { struct Point p; p.x = 10; p.y = 20; return 0;}
在C语言中,联合体(union)和枚举(enum)是两种非常有用的自定义数据类型,它们各自有不同的用途和特点。
9. 联合体(Union)
联合体允许存储不同类型的数据,但在同一时间只能存储其中的一种类型。它的大小由其中最大的成员决定。
语法
union Data { int i; float f; char str[20];};
示例
#include <stdio.h>#include <string.h>
union Data { int i; float f; char str[20];};
int main() { union Data data;
data.i = 10; printf("data.i : %d\n", data.i);
data.f = 220.5; printf("data.f : %f\n", data.f);
strcpy(data.str, "C Programming"); printf("data.str : %s\n", data.str);
return 0;}
在这个例子中,data
联合体可以存储一个整数、一个浮点数或者一个字符串,但是在同一时间只能存储其中之一。每次赋值会覆盖之前的值。
10. 枚举(Enum)
枚举是一种用户定义的数据类型,它由一组具名的整型常量组成。这些常量代表了一系列相关的值,通常用于表示状态、选项或标志。
语法
enum Day { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday};
示例
#include <stdio.h>
enum Day { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday};
int main() { enum Day today;
today = Wednesday; printf("Day %d\n", today);
return 0;}
在这个例子中,Day
枚举类型定义了一周的七天,每个枚举常量默认从0开始递增。Wednesday
对应的值为3。
联合体和枚举的结合使用
联合体和枚举可以结合使用,例如定义一个可以存储不同类型数据的结构体,并用枚举来指示当前存储的数据类型。
示例
#include <stdio.h>#include <string.h>
enum DataType { INT, FLOAT, STRING};
union Data { int i; float f; char str[20];};
struct Container { enum DataType type; union Data data;};
int main() { struct Container c;
c.type = INT; c.data.i = 42; if (c.type == INT) { printf("Integer: %d\n", c.data.i); }
c.type = FLOAT; c.data.f = 3.14; if (c.type == FLOAT) { printf("Float: %f\n", c.data.f); }
c.type = STRING; strcpy(c.data.str, "Hello, World!"); if (c.type == STRING) { printf("String: %s\n", c.data.str); }
return 0;}
技巧
实现offsetof
offsetof可以获取字段相对于结构体的偏移
#define offsetof(type, member) ((const unsigned long)&((type*)0)->member)
通过字段指针获取整个结构体的指针
offsetof 宏定义在 <stddef.h>
#include <stdio.h>#include <stddef.h>
struct Person { char name[20]; int age;};
// 通过字段指针获取整个结构体的指针#define container_of(ptr, type, member) ((type *)((char *)(ptr) - offsetof(type, member)))
int main() { struct Person p = {"John", 30}; int *age_ptr = &p.age;
// 使用 container_of 宏获取指向整个结构体的指针 struct Person *p_ptr = container_of(age_ptr, struct Person, age);
// 验证结果 printf("Name: %s, Age: %d\n", p_ptr->name, p_ptr->age);
return 0;}