标准库
输入和输出 {#stdio-1}
标准文件
C 语言把所有的设备都当作文件。所以设备(比如显示器)被处理的方式与文件相同。以下三个文件会在程序执行时自动打开,以便访问键盘和屏幕。
标准文件 | 文件指针 | 设备 |
---|---|---|
标准输入 | stdin |
键盘 |
标准输出 | stdout |
屏幕 |
标准错误 | stderr |
屏幕 |
getchar()
函数
getchar()
函数从屏幕读取下一个可用的字符,并把它返回为一个整数。
语法
int getchar(void);
返回值
- 成功时:返回读取到的字符,以
int
类型表示。 - 失败时:若到达文件结束或发生错误,返回
EOF
。
示例
int ch = getchar();
if (ch != EOF) {
printf("You entered: %c\n", ch);
}
putchar()
函数
putchar()
函数把字符输出到屏幕上,并返回相同的字符。
语法
int putchar(int ch);
ch
: 要输出的字符(以int
类型传递)。
返回值
- 成功时:返回写入的字符。
- 失败时:若发生错误,返回
EOF
。
示例
putchar('A'); // 输出字符 'A'
gets()
函数
gets()
函数用于从标准输入读取一行字符,直到换行符或文件结束符。
警告:
gets()
不安全,容易导致缓冲区溢出,建议使用fgets()
替代。
语法
char *gets(char *str);
str
: 指向存储读取数据的字符数组。
返回值
- 成功时:返回
str
的指针。 - 失败时:若发生错误或到达文件结束,返回
NULL
。
示例
char str[100];
if (gets(str) != NULL) {
printf("You entered: %s\n", str);
}
puts()
函数
puts()
函数用于将一个字符串写到标准输出,并在末尾添加一个换行符。
语法
int puts(const char *str);
str
: 要输出的字符串。
返回值
- 成功时:返回非负数。
- 失败时:若发生错误,返回
EOF
。
示例
puts("Hello, World!"); // 输出字符串并换行
scanf()
函数
scanf()
函数用于从标准输入读取格式化输入。
语法
int scanf(const char *format, ...);
format
: 格式字符串,指定要读取的数据类型。...
: 输入变量的地址。
返回值
- 成功时:返回成功读取的项数。
- 失败时:若读取失败,返回
EOF
。
示例
int num;
scanf("%d", &num); // 从标准输入读取一个整数
printf("You entered: %d\n", num);
printf()
函数
printf()
函数用于向标准输出打印格式化的文本。
语法
int printf(const char *format, ...);
format
: 格式字符串,指定要输出的数据格式。...
: 要输出的数据项。
返回值
- 成功时:返回输出的字符数。
- 失败时:若发生错误,返回负数。
示例
int num = 10;
printf("The number is %d\n", num); // 输出格式化字符串
format参考表格
对于format,可以参考下面的表格:
格式说明符 | 说明 | printf 示例 |
scanf 示例 |
---|---|---|---|
%d |
有符号十进制整数 | printf("%d", 42); |
scanf("%d", &var); |
%i |
有符号十进制整数(与 %d 类似) |
printf("%i", 42); |
scanf("%i", &var); |
%u |
无符号十进制整数 | printf("%u", 42u); |
scanf("%u", &var); |
%o |
无符号八进制整数 | printf("%o", 42u); |
scanf("%o", &var); |
%x |
无符号十六进制整数(小写) | printf("%x", 42u); |
scanf("%x", &var); |
%X |
无符号十六进制整数(大写) | printf("%X", 42u); |
scanf("%X", &var); |
%f |
浮点数(小数表示) | printf("%f", 3.14); |
scanf("%f", &var); |
%e |
浮点数(科学计数法,小写) | printf("%e", 3.14); |
scanf("%e", &var); |
%E |
浮点数(科学计数法,大写) | printf("%E", 3.14); |
scanf("%E", &var); |
%g |
自动选择 %f 或 %e |
printf("%g", 3.14); |
scanf("%g", &var); |
%G |
自动选择 %f 或 %E |
printf("%G", 3.14); |
scanf("%G", &var); |
%c |
单个字符 | printf("%c", 'A'); |
scanf("%c", &var); |
%s |
字符串,直到空白字符结束 | printf("%s", "Hello"); |
scanf("%s", str); |
%p |
指针地址 | printf("%p", ptr); |
不适用 |
%% |
输出一个 % 符号 |
printf("%%"); |
不适用 |
其他常用格式说明符
格式说明符 | 说明 | 示例 |
---|---|---|
%*d |
跳过整数,不读取或保存,d可以替换成其它的 | scanf("%*d %d", &var); |
%[ ] |
自定义字符集(用于读取指定的字符范围) | scanf("%[a-z]", str); |
%[^ ] |
非指定字符集(读取直到遇到空白字符) | scanf("%[^ ]", str); |
%.nf |
精确到小数点后n位,f可以替换成其它的 | scanf("%9s", str); |
%nf |
总宽度位n位,超过的舍去,不够的用空格补全 | scanf("%9s", str); printf("%9s", str) |
文件读写 {#stdio-2}
库变量
变量 | 描述 |
---|---|
size_t 无符号整数类型 |
是 sizeof 关键字的结果,表示对象大小。 |
FILE 文件流类型 |
适合存储文件流信息的对象类型。 |
库宏
序号 | 宏 & 描述 |
---|---|
NULL |
这个宏是一个空指针常量的值。 |
EOF |
这个宏是一个表示已经到达文件结束的负整数。 |
stderr 、stdin 和 stdout |
这些宏是指向 FILE 类型的指针,分别对应于标准错误、标准输入和标准输出流。 |
fopen()
& fclose()
函数
fopen()
和 fclose()
函数用于文件的打开和关闭。fopen()
用于打开文件并返回文件指针,fclose()
用于关闭打开的文件。
fopen()
语法
FILE *fopen(const char *filename, const char *mode);
filename
: 文件的路径或名称。mode
: 文件打开模式,常见的有:"r"
: 只读模式。"w"
: 只写模式,文件不存在时创建文件,存在时清空文件。"a"
: 追加模式,文件不存在时创建文件,存在时不清空文件。"rb"
,"wb"
,"ab"
: 二进制模式。"r+"
: 读写模式。"w+"
: 读写模式,文件不存在时创建文件,存在时清空文件。
返回值
- 成功时:返回一个指向
FILE
类型的指针。 - 失败时:返回
NULL
。
fclose()
语法
int fclose(FILE *stream);
stream
: 由fopen()
返回的文件指针。
返回值
- 成功时:返回
0
。 - 失败时:返回
EOF
。
示例
FILE *file = fopen("example.txt", "w");
if (file == NULL) {
printf("File opening failed.\n");
} else {
// 处理文件...
fclose(file);
}
fputc()
& fputs()
函数
fputc()
和 fputs()
用于向文件写入数据。fputc()
用于写单个字符,而 fputs()
用于写字符串。
fputc()
语法
int fputc(int character, FILE *stream);
character
: 要写入的字符。stream
: 文件指针。
返回值
- 成功时:返回写入的字符。
- 失败时:返回
EOF
。
fputs()
语法
int fputs(const char *str, FILE *stream);
str
: 要写入的字符串。stream
: 文件指针。
返回值
- 成功时:返回非负值。
- 失败时:返回
EOF
。
示例
FILE *file = fopen("output.txt", "w");
if (file != NULL) {
fputc('A', file); // 写入单个字符
fputs("Hello, World!", file); // 写入字符串
fclose(file);
}
fgetc()
& fgets()
函数
fgetc()
和 fgets()
用于从文件中读取数据。fgetc()
用于读取单个字符,fgets()
用于读取一行字符。
fgetc()
语法
int fgetc(FILE *stream);
stream
: 文件指针。
返回值
- 成功时:返回读取的字符(类型为
int
)。 - 失败时:返回
EOF
。
fgets()
语法
char *fgets(char *str, int num, FILE *stream);
str
: 存储读取内容的缓冲区。num
: 最大字符数(包括空字符'\0'
)。stream
: 文件指针。
返回值c
- 成功时:返回
str
。 - 失败时:返回
NULL
。
示例
FILE *file = fopen("example.txt", "r");
if (file != NULL) {
char ch = fgetc(file); // 读取单个字符
printf("%c\n", ch);
char buffer[100];
fgets(buffer, 100, file); // 读取一行
printf("%s\n", buffer);
fclose(file);
}
fprintf()
& fscanf()
函数
fprintf()
和 fscanf()
用于格式化文件输入输出,与 printf()
和 scanf()
类似,但操作的是文件而非标准输入输出。
fprintf()
语法
int fprintf(FILE *stream, const char *format, ...);
stream
: 文件指针。format
: 格式字符串,类似printf()
。
返回值
- 成功时:返回写入的字符数。
- 失败时:返回负值。
fscanf()
语法
int fscanf(FILE *stream, const char *format, ...);
stream
: 文件指针。format
: 格式字符串,类似scanf()
。
返回值
- 成功时:返回成功读取的项数。
- 失败时:返回
EOF
。
示例
FILE *file = fopen("data.txt", "w");
if (file != NULL) {
fprintf(file, "Name: %s, Age: %d\n", "John", 30); // 写入格式化数据
fclose(file);
}
FILE *file2 = fopen("data.txt", "r");
if (file2 != NULL) {
char name[20];
int age;
fscanf(file2, "Name: %s, Age: %d", name, &age); // 读取格式化数据
printf("Name: %s, Age: %d\n", name, age);
fclose(file2);
}
fread()
& fwrite()
函数
fread()
和 fwrite()
用于读取和写入二进制数据,通常用于文件的二进制操作。
fread()
语法
size_t fread(void *ptr, size_t size, size_t count, FILE *stream);
ptr
: 指向存储数据的内存缓冲区。size
: 每个元素的字节数。count
: 要读取的元素个数。stream
: 文件指针。
返回值
- 成功时:返回实际读取的元素数。
- 失败时:返回 0。
fwrite()
语法
size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream);
ptr
: 指向要写入的数据的内存地址。size
: 每个元素的字节数。count
: 要写入的元素个数。stream
: 文件指针。
返回值
- 成功时:返回实际写入的元素数。
- 失败时:返回 0。
示例
FILE *file = fopen("binary.dat", "wb");
if (file != NULL) {
int data[] = {1, 2, 3, 4, 5};
fwrite(data, sizeof(int), 5, file); // 写入整数数组
fclose(file);
}
FILE *file2 = fopen("binary.dat", "rb");
if (file2 != NULL) {
int data[5];
fread(data, sizeof(int), 5, file2); // 读取整数数组
fclose(file2);
}
fflush()
函数
fflush()
用于刷新输出缓冲区,强制将缓冲区中的数据写入文件。
fflush()
语法
int fflush(FILE *stream);
stream
: 文件指针。
返回值
- 成功时:返回
0
。 - 失败时:返回
EOF
。
示例
FILE *file = fopen("output.txt", "w");
if (file != NULL) {
fputs("Hello", file); // 写入数据
fflush(file); // 强制写入文件
fclose(file);
}
fseek()
函数
fseek()
用于设置文件指针的位置,用于随机访问文件中的内容。
语法
int fseek(FILE *stream, long offset, int whence);
stream
: 文件指针。offset
: 偏移量,指定从whence
参数指定的位置开始偏移的字节数。whence
: 位置标志,常见值:SEEK_SET
: 从文件开头计算偏移。SEEK_CUR
: 从当前位置计算偏移。SEEK_END
: 从文件末尾计算偏移。
返回值
- 成功时:返回
0
。 - 失败时:返回
-1
。
ftell()
函数
ftell()
用于获取文件指针相对于文件起始位置的当前偏移量。
语法
long ftell(FILE *stream);
stream
: 文件指针,通常是通过fopen()
打开的文件。
返回值
- 成功时:返回文件指针相对于文件开头的偏移量,以字节为单位。
- 失败时:返回
-1L
,表示发生错误。此时可以使用perror()
或检查errno
进行诊断。
示例
#include <stdio.h>
int main() {
FILE *file = fopen("example.txt", "r"); // 打开文件
if (file == NULL) {
perror("Error opening file");
return 1;
}
long offset = ftell(file); // 获取文件指针的偏移量
if (offset == -1L) {
perror("Error getting file position");
fclose(file);
return 1;
}
printf("Current file offset: %ld\n", offset);
fclose(file);
return 0;
}
说明
ftell()
在文本模式下的行为可能受操作系统的影响,尤其在处理换行符时,可能存在平台差异。为了避免这种差异,可以使用二进制模式打开文件。
内存管理 {#stdlib-1}
malloc()
函数
malloc()
函数用于分配一块指定大小的内存,返回指向这块内存的指针。内存不会被初始化为0。
语法
void *malloc(size_t size);
size
:需要分配内存的大小,以字节为单位。
返回值
- 成功时:返回一个指向分配内存块的
void*
指针。需要将它强制类型转换为所需的数据类型。 - 失败时:若无法分配内存,则会返回NULL。
示例
int *ptr = (int *)malloc(10 * sizeof(int)); // 分配 10 个整数大小的内存
if (ptr == NULL) {
printf("Memory allocation failed.\n");
}
calloc()
函数
calloc()
用于分配指定数量和大小的内存,并将分配的内存初始化为零。
语法
void *calloc(size_t num, size_t size);
num
: 要分配的内存块数量。size
: 每个内存块的大小(以字节为单位)。
返回值
- 成功时:返回指向分配内存的指针。
- 失败时:返回
NULL
。
示例
int *arr = (int *)calloc(5, sizeof(int)); // 分配 5 个整数并初始化为 0
if (arr == NULL) {
printf("Memory allocation failed.\n");
} else {
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]); // 输出 0 0 0 0 0
}
free(arr);
}
说明
calloc()
会将分配的内存初始化为零,这与malloc()
不同,后者分配的内存内容是不确定的(可能是垃圾值)。
realloc()
函数
realloc()
用于调整已分配内存块的大小。它可以增加或减少内存的大小,并且可以在必要时移动内存位置。
语法
void *realloc(void *ptr, size_t new_size);
ptr
: 指向已分配内存的指针(由malloc
、calloc
或realloc
分配的内存)。new_size
: 新的内存大小(以字节为单位)。
返回值
- 成功时:返回指向调整后内存的指针(可能是原来的内存,也可能是一个新的位置)。
- 失败时:返回
NULL
,此时原内存保持不变。
示例
int *arr = (int *)malloc(5 * sizeof(int)); // 原先分配了 5 个整数
if (arr != NULL) {
for (int i = 0; i < 5; i++) {
arr[i] = i + 1;
}
// 重新调整内存大小,增加到 10 个整数
arr = (int *)realloc(arr, 10 * sizeof(int));
if (arr != NULL) {
for (int i = 5; i < 10; i++) {
arr[i] = i + 1; // 填充新分配的内存
}
for (int i = 0; i < 10; i++) {
printf("%d ", arr[i]); // 输出 1 2 3 4 5 6 7 8 9 10
}
free(arr);
}
}
说明
realloc()
会尝试在原位置增加或减少内存,如果原位置不够,可能会分配新的内存块,并将原内存内容复制过去。- 重要:如果
realloc()
失败,原来的内存块不会被释放,程序应该在使用realloc()
后检查返回值。
free()
函数
free()
用于释放动态分配的内存块,以避免内存泄漏。
语法
void free(void *ptr);
ptr
: 指向已分配内存块的指针。如果ptr
为NULL
,则free()
不做任何操作。
示例
int *arr = (int *)malloc(5 * sizeof(int));
if (arr != NULL) {
// 使用内存...
free(arr); // 释放内存
}
说明
free()
仅释放通过malloc
、calloc
或realloc
动态分配的内存。- 释放后,指针仍然是悬空指针,应该将其设置为
NULL
来避免使用已释放的内存。
memcpy()
函数
memcpy()
用于从一个内存位置复制数据到另一个内存位置。
语法
void *memcpy(void *dest, const void *src, size_t n);
dest
: 目标内存地址,数据将被复制到此。src
: 源内存地址,数据将从这里复制。n
: 要复制的字节数。
返回值
- 返回目标地址
dest
。
示例
int src[] = {1, 2, 3, 4, 5};
int dest[5];
memcpy(dest, src, 5 * sizeof(int)); // 将 src 数组的内容复制到 dest
说明
memcpy()
是一个简单的内存复制函数,通常用于复制内存块或数组。- 注意:
memcpy()
不会检查源和目标区域是否重叠。如果内存区域重叠,应该使用memmove()
(见下文)。
memmove()
函数
memmove()
类似于 memcpy()
,但它能够正确处理源和目标内存区域重叠的情况。
语法
void *memmove(void *dest, const void *src, size_t n);
dest
: 目标内存地址,数据将被复制到此。src
: 源内存地址,数据将从这里复制。n
: 要复制的字节数。
返回值
- 返回目标地址
dest
。
示例
char str[] = "Hello, World!";
memmove(str + 7, str, 6); // 将 "Hello," 移动到 "World!" 前面
printf("%s\n", str); // 输出 "Hello, Hello!"
说明
memmove()
会正确处理源和目标内存区域重叠的情况,它在复制过程中会使用临时缓冲区来避免数据损坏。- 如果不需要处理内存重叠的情况,
memcpy()
更高效。
string.h
strlen()
函数
strlen()
用于计算字符串的长度,不包括终止符 \0
。
语法
size_t strlen(const char *str);
str
: 要计算长度的字符串。
返回值
- 返回字符串
str
的长度(不包括\0
)。
示例
char str[] = "Hello, World!";
size_t len = strlen(str); // len 为 13
strcpy()
函数
strcpy()
用于将源字符串复制到目标字符串中,包含终止符 \0
。
语法
char *strcpy(char *dest, const char *src);
dest
: 目标字符串,数据将被复制到此。src
: 源字符串,数据将从这里复制。
返回值
- 返回目标字符串
dest
。
示例
char src[] = "Hello";
char dest[10];
strcpy(dest, src); // dest 变为 "Hello"
strncpy()
函数
strncpy()
类似于 strcpy()
,但可以指定要复制的字符数。如果 src
的长度小于 n
,则 dest
会用 \0
填充。
语法
char *strncpy(char *dest, const char *src, size_t n);
dest
: 目标字符串。src
: 源字符串。n
: 要复制的字符数。
返回值
- 返回目标字符串
dest
。
示例
char src[] = "Hello";
char dest[10];
strncpy(dest, src, 3); // dest 变为 "Hel"
strcat()
函数
strcat()
用于将源字符串追加到目标字符串的末尾,覆盖目标字符串原有的终止符 \0
,并在新字符串末尾添加一个新的 \0
。
语法
char *strcat(char *dest, const char *src);
dest
: 目标字符串,源字符串将被追加到此。src
: 源字符串,数据将从这里复制。
返回值
- 返回目标字符串
dest
。
示例
char dest[20] = "Hello, ";
char src[] = "World!";
strcat(dest, src); // dest 变为 "Hello, World!"
strncat()
函数
strncat()
类似于 strcat()
,但可以指定要追加的字符数。
语法
char *strncat(char *dest, const char *src, size_t n);
dest
: 目标字符串。src
: 源字符串。n
: 要追加的字符数。
返回值
- 返回目标字符串
dest
。
示例
char dest[20] = "Hello, ";
char src[] = "World!";
strncat(dest, src, 3); // dest 变为 "Hello, Wor"
strcmp()
函数
strcmp()
用于逐字符比较两个字符串,比较结果为:
- 0:如果两个字符串相等。
- 负值:如果
str1
小于str2
。 - 正值:如果
str1
大于str2
。
语法
int strcmp(const char *str1, const char *str2);
str1
: 第一个字符串。str2
: 第二个字符串。
返回值
- 返回整数,表示字符串之间的差异。
示例
int result = strcmp("apple", "banana"); // result 为负值
strncmp()
函数
strncmp()
与 strcmp()
类似,但最多比较前 n
个字符。
语法
int strncmp(const char *str1, const char *str2, size_t n);
str1
: 第一个字符串。str2
: 第二个字符串。n
: 比较的最大字符数。
返回值
- 返回整数,表示字符串之间的差异。
示例
int result = strncmp("apple", "apricot", 3); // result 为 0
说明
strchr()
函数
strchr()
用于在字符串中查找第一次出现的字符,返回指向该字符的指针。
语法
char *strchr(const char *str, int ch);
str
: 要查找的字符串。ch
: 要查找的字符。
返回值
- 返回指向第一个匹配字符的指针,如果未找到则返回
NULL
。
示例
char *result = strchr("Hello, World!", 'o'); // result 指向第一个 'o'
strrchr()
函数
strrchr()
类似于 strchr()
,但从字符串末尾开始查找。
语法
char *strrchr(const char *str, int ch);
str
: 要查找的字符串。ch
: 要查找的字符。
返回值
- 返回指向最后一个匹配字符的指针,如果未找到则返回
NULL
。
示例
char *result = strrchr("Hello, World!", 'o'); // result 指向最后一个 'o'
strstr()
函数
strstr()
用于查找子字符串在主字符串中的第一次出现,返回指向该子字符串的指针。
语法
char *strstr(const char *haystack, const char *needle);
haystack
: 主字符串。needle
: 要查找的子字符串。
返回值
- 返回指向子字符串第一次出现的位置指针,如果未找到则返回
NULL
。
示例
char *result = strstr("Hello, World!", "World"); // result 指向 "World!"
strtok()
函数
strtok()
用于分割字符串,以指定的分隔符进行分割,返回分割的子字符串。
语法
char *strtok(char *str, const char *delim);
str
: 要分割的字符串(第一次调用传入,后续调用传NULL
)。delim
: 分隔符字符串。
返回值
- 返回指向分割出的子字符串的指针,如果没有更多分割部分则返回
NULL
。
示例
char str[] = "Hello,World";
char *token = strtok(str, ",");
while (token != NULL) {
printf("%s\n", token);
token = strtok(NULL, ",");
}
说明
strtok()
会改变输入字符串,将分隔符替换为\0
,因此需要注意原始字符串的不可变性。
setjmp.h
库变量
变量 | 描述 |
---|---|
jmp_buf |
用于保存调用环境,包括栈指针、指令指针和寄存器等。在执行 setjmp() 时,这些环境信息会被保存到 jmp_buf 类型的变量中。 |
setjmp()
宏
setjmp()
用于保存当前的堆栈上下文(包括程序计数器、寄存器值等),使得之后可以通过 longjmp()
跳回到这个保存的点。
语法
int setjmp(jmp_buf env);
env
: 一个jmp_buf
类型的变量,用于保存跳转点的堆栈上下文。
返回值
- 第一次调用
setjmp()
:返回 0。 - 通过
longjmp()
跳转回来时:返回一个非零值,这个值由longjmp()
的第二个参数决定。
longjmp()
函数
longjmp()
用于通过跳转回先前由 setjmp()
保存的位置。它恢复程序的执行状态并返回给 setjmp()
,使得可以模拟错误处理。
语法
void longjmp(jmp_buf env, int val);
env
: 一个jmp_buf
类型的变量,保存跳转点的堆栈上下文。val
: 返回给setjmp()
的值。如果val
为 0,setjmp()
返回 1。
返回值
longjmp()
不会返回,它直接跳转到之前的setjmp()
位置,并将setjmp()
返回非零值。
示例–异常处理
#include <stdio.h>
#include <setjmp.h>
jmp_buf env;
int envType = 0;
int dev(const int a, const int b) {
if (b==0) {
longjmp(env, 1);
}
return a / b;
}
int main() {
envType = setjmp(env);
if (envtype == 0) {
int a = dev(1, 0);
printf("%d\n", a);
} else if (envType == 1) {
printf("ZeroDivisionError");
}
return 0;
}
封装简易的try{} cathch{} finally{}
和throw
如下:
#include <stdio.h>
#include <setjmp.h>
jmp_buf env;
int envType = 0;
#define ZeroDivisionError 1
#define try envType = setjmp(env); if (envType == 0)
#define catch(n) else if (envType == n)
#define finally else
#define throw(n) longjmp(env, n);
int dev(const int a, const int b) {
if (b==0) {
throw(ZeroDivisionError);
}
return a / b;
}
int main() {
try {
int a = dev(1, 0);
printf("%d\n", a);
} catch(ZeroDivisionError) {
printf("Division by zero")
}
return 0;
}
stdarg.h
库变量
变量 | 描述 |
---|---|
va_list |
一个适用于 va_start()、va_arg() 和 va_end() 这三个宏存储信息的类型。 |
va_start()
宏
va_start()
用于初始化 va_list
类型的变量,以便使用 va_arg()
访问函数参数列表中的额外参数。
语法
void va_start(va_list ap, last_arg);
ap
:va_list
类型的变量,用于访问函数的可变参数。last_arg
: 可变参数列表中的最后一个固定参数,用于计算可变参数的起始位置。
va_arg()
宏
va_arg()
用于获取可变参数,并且会自动调整指向下一个参数的位置。
语法
type va_arg(va_list ap, type);
ap
:va_list
类型的变量,它指向当前可变参数列表的当前位置。type
: 参数的类型,va_arg()
将从ap
中获取下一个参数并将其转换为此类型。
返回值
- 返回当前参数,并将
ap
移动到下一个参数的位置。
va_end()
宏
va_end()
用于结束可变参数列表的访问,它应在访问完所有可变参数后调用。
语法
void va_end(va_list ap);
ap
:va_list
类型的变量,指向可变参数列表。
示例
#include <stdio.h>
#include <stdarg.h>
void print_numbers(int count, ...) {
va_list ap;
va_start(ap, count);
for (int i = 0; i < count; i++) {
int num = va_arg(ap, int); // 获取下一个整数参数
printf("%d ", num);
}
va_end(ap); // 结束可变参数的处理
printf("\n");
}
int main() {
print_numbers(3, 10, 20, 30); // 输出: 10 20 30
print_numbers(2, 5, 15); // 输出: 5 15
return 0;
}
math.h
这个库中所有可用的功能都带有一个 double 类型的参数,且都返回 double 类型的结果。
log()
函数
log()
用于计算一个数的自然对数(以 e 为底)。
语法
double log(double x);
x
: 输入值,必须为正数。
返回值
- 返回
x
的自然对数。
示例
double result = log(2.71828); // 返回值约为 1
log10()
函数
log10()
用于计算一个数的常用对数(以 10 为底)。
语法
double log10(double x);
x
: 输入值,必须为正数。
返回值
- 返回
x
的以 10 为底的对数。
示例
double result = log10(100); // 返回值为 2
pow()
函数
pow()
用于计算一个数的指定幂次。
语法
double pow(double base, double exp);
base
: 底数。exp
: 指数。
返回值
- 返回
base
的exp
次幂。
示例
double result = pow(2, 3); // 返回值为 8
sqrt()
函数
sqrt()
用于计算一个数的平方根。
语法
double sqrt(double x);
x
: 输入值,必须为非负数。
返回值
- 返回
x
的平方根。
示例
double result = sqrt(9); // 返回值为 3
ceil()
函数
ceil()
用于将一个数向上取整到最近的整数。
语法
double ceil(double x);
x
: 输入值。
返回值
- 返回不小于
x
的最小整数值。
示例
double result = ceil(3.14); // 返回值为 4
fabs()
函数
fabs()
用于计算一个数的绝对值。
语法
double fabs(double x);
x
: 输入值。
返回值
- 返回
x
的绝对值。
示例
double result = fabs(-5.5); // 返回值为 5.5
floor()
函数
floor()
用于将一个数向下取整到最近的整数。
语法
double floor(double x);
x
: 输入值。
返回值
- 返回不大于
x
的最大整数值。
示例
double result = floor(3.14); // 返回值为 3
stddef.h
offsetof()
宏
offsetof()
会生成一个类型为 size_t
的整型常量,它是一个结构成员相对于结构开头的字节偏移量。
语法
offsetof(type, member-designator)
- type -- 这是一个 class 类型,其中,member-designator 是一个有效的成员指示器。
- member-designator -- 这是一个 class 类型的成员指示器。
返回值
该宏返回类型为size_t
的值,表示type
中成员的偏移量。
示例
#include <stddef.h>
#include <stdio.h>
struct address {
char name[50];
char street[50];
int phone;
};
int main()
{
printf("address 结构中的 name 偏移 = %d 字节。\n",
offsetof(struct address, name)); // 50
printf("address 结构中的 street 偏移 = %d 字节。\n",
offsetof(struct address, street)); // 50
printf("address 结构中的 phone 偏移 = %d 字节。\n",
offsetof(struct address, phone)); // 100
return 0;
}
stdio.h
sprintf()
函数
sprintf()
用于将格式化的字符串写入指定的字符数组中,而不是输出到标准输出(如 printf()
所做的)。
语法
int sprintf(char *str, const char *format, ...);
str
: 字符数组,存储生成的格式化字符串。format
: 格式化字符串,类似于printf()
的格式,可以使用%d
、%s
等格式说明符。...
: 可变参数,表示要格式化的数据。
返回值
- 返回写入
str
中的字符总数,不包括终止符\0
。 - 如果出现错误,可能会返回负值。
示例
char buffer[50];
int num = 42;
double pi = 3.14159;
sprintf(buffer, "Number: %d, Pi: %.2f", num, pi);
// buffer 中将包含 "Number: 42, Pi: 3.14"
snprintf()
函数
snprintf()
用于将格式化的字符串写入指定的字符数组,并限制写入的字符数,避免缓冲区溢出。
语法
int snprintf(char *str, size_t size, const char *format, ...);
str
: 字符数组,存储生成的格式化字符串。size
: 字符数组的最大大小(包括终止符\0
)。确保写入数据不会超过此大小。format
: 格式化字符串,类似于printf()
的格式,可以使用%d
、%s
等格式说明符。...
: 可变参数,表示要格式化的数据。
返回值
- 如果写入的字符总数小于提供的数组大小,那么返回值是实际写入的字符数,不包括字符串结束符
\0
。如果写入的字符总数大于或等于提供的数组大小,返回值是所需的字符数,即完整格式化字符串的长度(不包括\0
)。 - 如果发生错误,可能返回负值。
示例
char buffer[50];
int num = 42;
double pi = 3.14159;
int len = snprintf(buffer, sizeof(buffer), "Number: %d, Pi: %.2f", num, pi);
// buffer 中将包含 "Number: 42, Pi: 3.14"
// len 返回 23(写入字符数,不包括 \0)
注意
snprintf()
不会写入超过size - 1
个字符(保留一个位置给\0
)。- 在使用
snprintf()
时,最好使用返回值来检查是否有足够的空间来存储完整的格式化字符串。
stdlib.h
内存管理部分见内存管理
atoi()
函数
atoi()
用于将字符串转换为 int
类型的整数。
语法
int atoi(const char *str);
str
: 输入字符串,必须是数字字符串(例如 "123"),可以包含前导空白字符和一个可选的正负号。
返回值
- 成功时,返回转换后的整数。
- 如果字符串不包含有效数字,则返回
0
。
示例
int num = atoi("123"); // num 为 123
atof()
函数
atof()
用于将字符串转换为 double
类型的浮点数。
语法
double atof(const char *str);
str
: 输入字符串,必须是数字字符串,格式为浮点数(例如 "123.45")。
返回值
- 成功时,返回转换后的浮点数。
- 如果字符串不包含有效数字,则返回
0.0
。
示例
double num = atof("123.45"); // num 为 123.45
atol()
函数
atol()
用于将字符串转换为 long
类型的整数。
语法
long atol(const char *str);
str
: 输入字符串,必须是数字字符串(例如 "123456789")。
返回值
- 成功时,返回转换后的
long
类型整数。 - 如果字符串不包含有效数字,则返回
0
。
示例
long num = atol("123456789"); // num 为 123456789
exit()
函数
exit()
用于立即终止程序的执行,并返回一个状态码。
语法
void exit(int status);
status
: 程序的退出状态。常用状态码:EXIT_SUCCESS
:表示成功退出。EXIT_FAILURE
:表示失败退出。
示例
if (error) {
exit(EXIT_FAILURE); // 程序出错时退出并返回失败状态码
}
system()
函数
system()
用于执行系统命令,允许程序调用操作系统的外部命令。
语法
int system(const char *command);
command
: 要执行的命令字符串(例如"ls"
、"dir"
等)。
返回值
- 成功执行时,返回命令的退出状态码。
- 失败时,返回非零值(如果命令不可用或执行失败)。
示例
system("ls"); // 执行 ls 命令列出当前目录下的文件
qsort()
函数
qsort()
用于对数组进行快速排序。
语法
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
base
: 数组的起始地址。nmemb
: 数组元素的数量。size
: 每个元素的大小(以字节为单位)。compar
: 指向比较函数的指针,该函数确定排序顺序。
返回值
- 该函数没有返回值,排序结果直接应用于数组。
示例
int compare(const void *a, const void *b) {
return (*(int *)a - *(int *)b);
}
int arr[] = {5, 2, 9, 1, 5, 6};
qsort(arr, 6, sizeof(int), compare); // 对数组进行排序
stdbool.h
定义了bool
相关的宏:
bool
:#define bool _Bool
true
:#define true 1
false
:#define false 0