文章目录
引言
在C语言中,<stdlib.h>
是一个重要的头文件,它包含了一些标准库函数,提供了内存分配、随机数生成、字符串转换等功能。本博客将深入解析 <stdlib.h>
头文件,介绍其中一些常用函数的用法和实现原理。
1. <stdlib.h>
概览
<stdlib.h>
是 C 标准库的一部分,它定义了一些宽泛的实用函数。这些函数通常涉及内存管理、伪随机数生成、整数转换等方面。
1.1 头文件包含
在使用 <stdlib.h>
头文件之前,我们通常会在程序中包含以下语句:
#include <stdlib.h>
这样可以确保我们在程序中使用标准库函数时能够正确调用相应的功能。
2. 内存管理函数
2.1 malloc
函数
- 功能:
malloc
函数用于在堆上分配一块指定大小的内存空间。成功时返回指向分配内存的指针,失败时返回NULL
。 - 原型:
void* malloc(size_t size);
#include <stdio.h> #include <stdlib.h> int main() { // 定义一个指针,分配包含 5 个整数的内存块 int *dynamicArray = (int *)malloc(5 * sizeof(int)); // 检查内存是否成功分配 if (dynamicArray == NULL) { printf( "内存分配失败\n"); return 1; // 返回错误代码 } // 向动态数组中写入数据 int i; for (i = 0; i < 5; ++i) { dynamicArray[i] = i * 2; } // 输出动态数组的内容 printf("动态数组的内容:\n"); for (i = 0; i < 5; ++i) { printf("%d ", dynamicArray[i]); } // 释放动态分配的内存 free(dynamicArray); return 0; }
动态数组的内容: 0 2 4 6 8
2.2 calloc
函数
- 功能:
calloc
函数用于在堆上分配一块指定数量和大小的内存空间,与malloc
不同的是,calloc
会将分配的内存块初始化为零。 - 原型:
void* calloc(size_t num, size_t size);
例如
int*
初始化就是0char*
初始化就是’\0’
#include <stdio.h> #include <stdlib.h> int main() { // 定义一个指针,用于存储分配的内存地址 int *dynamicArray; // 使用 calloc 分配包含 5 个整数的内存块 dynamicArray = (int *)calloc(5, sizeof(int)); // 检查内存是否成功分配 if (dynamicArray == NULL) { fprintf(stderr, "内存分配失败\n"); return 1; // 返回错误代码 } // 输出动态数组的内容,此时数组已被初始化为零 printf("动态数组的内容:\n"); int i; for (i = 0; i < 5; ++i) { printf("%d ", dynamicArray[i]); } // 释放动态分配的内存 free(dynamicArray); return 0; }
动态数组的内容: 0 0 0 0 0
2.3 realloc
函数
- 功能:
realloc
函数用于修改之前由malloc
、calloc
或realloc
分配的内存块的大小。它可以用于扩大或缩小内存块。 - 原型:
void* realloc(void* ptr, size_t size);
#include <stdio.h> #include <stdlib.h> int main() { // 初始分配 10 个整数大小的内存块 int *arr = (int *)malloc(10 * sizeof(int)); if (arr == NULL) { fprintf(stderr, "内存分配失败\n"); return 1; } printf("初始分配内存后的地址:%p\n", (void *)arr); // 使用 realloc 缩小内存块到 5 个整数大小 int *newArr = (int *)realloc(arr, 5 * sizeof(int)); if (newArr == NULL) { fprintf(stderr, "内存重新分配失败\n"); free(arr); // 如果 realloc 失败,需要释放原始的内存块 return 1; } printf("缩小内存后的地址:%p\n", (void *)newArr); // 现在 newArr 可以用于存储 5 个整数 // 不要忘记释放内存 free(newArr); return 0; }
2.4 free
函数
- 功能:
free
函数用于释放之前由malloc
、calloc
或realloc
分配的内存空间。释放后,该指针不再指向有效的内存区域。 - 原型:
void free(void* ptr);
// 例子 free(arr);
3. 随机数生成函数
3.1 rand
函数
- 功能:
rand
函数用于生成一个伪随机数。每次调用rand
都会返回一个范围在 0 到RAND_MAX
之间的整数。 - 原型:
int rand(void);
请注意,rand 函数生成的是伪随机数,其实际上是通过一定的算法计算的,因此不是真正的随机数。
#include <stdio.h> #include <stdlib.h> int main() { int randomNum1 = rand(); int randomNum2 = rand(); // 打印随机数 printf("Random Number 1: %d\n", randomNum1); printf("Random Number 2: %d\n", randomNum2); return 0; }
// 第一次运行 Random Number 1: 41 Random Number 2: 18467 // 第二次运行 Random Number 1: 41 Random Number 2: 18467 ...
3.2 srand
函数
- 功能:
srand
函数用于设置rand
函数的种子值,以便生成不同的随机数序列。 - 原型:
void srand(unsigned int seed);
#include <stdio.h> #include <stdlib.h> #include <time.h> int main() { // 没有使用 srand 设置种子 printf("未使用 srand:\n"); int i; for (i = 0; i < 5; ++i) { printf("%d ", rand()); } // 使用 srand 设置种子 srand(time(NULL)); // 42 只是一个示例种子值,可以是任何值 printf("\n使用 srand:\n"); for (i = 0; i < 5; ++i) { printf("%d ", rand()); } return 0; }
// 第一次运行 未使用 srand: 41 18467 6334 26500 19169 使用 srand: 29346 6213 16299 17151 17694 // 第二次运行 未使用 srand: 41 18467 6334 26500 19169 使用 srand: 29372 26664 28140 13050 1907 ...
在这个例子中,
srand(time(NULL))
使用当前时间作为随机数生成器的种子。由于时间每次都在变化,这样就能确保每次运行程序都会得到不同的随机数序列。
4. 字符串转换函数
4.1 atoi
函数
- 功能:
atoi
函数用于将字符串转换为整数。 - 原型:
int atoi(const char* str);
#include <stdio.h> #include <stdlib.h> int main() { // 定义一个字符串 char str1[] = "12345"; char str2[] = "12345abdc"; // 使用atoi将字符串转换为整数 int num1 = atoi(str1); int num2 = atoi(str2); // 打印结果 printf("String str1: %s\n", str1); printf("Integer int1: %d\n", num1); printf("String str2: %s\n", str2); printf("Integer int2: %d\n", num2); return 0; }
String str1: 12345 Integer int1: 12345 String str2: 12345abdc Integer int2: 12345
4.2 atof
函数
- 功能:
atof
函数用于将字符串转换为浮点数。 - 原型:
double atof(const char* str);
#include <stdio.h> #include <stdlib.h> int main() { // 定义字符串 char str1[] = "12345.137"; char str2[] = "12345.111abdc"; // 使用atof将字符串转换为浮点数 double num1 = atof(str1); double num2 = atof(str2); // 打印结果 printf("字符串 str1:%s\n", str1); printf("浮点数 num1:%lf\n", num1); printf("字符串 str2:%s\n", str2); printf("浮点数 num2:%lf\n", num2); return 0; }
字符串 str1:12345.137 浮点数 num1:12345.137000 字符串 str2:12345.111abdc 浮点数 num2:12345.111000
4.3 itoa
函数
- 功能:
itoa
函数用于将整数转换为字符串。它接受三个参数:要转换的整数value
,存储结果的字符串指针str
,和进制base
。base
可以是 2 到 36 之间的任意值,表示输出的字符串使用的进制。 - 原型:
char* itoa(int value, char* str, int base);
#include <stdio.h> #include <stdlib.h> int main() { // 定义整数 int num1 = 12345; int num2 = -6789; // 定义足够大的字符数组来存储转换后的字符串 char str1[20]; char str2[20]; // 使用 itoa 将整数转换为字符串 itoa(num1, str1, 10); // 第三个参数是基数,这里使用10进制 itoa(num2, str2, 10); // 打印结果 printf("整数 num1:%d\n", num1); printf("字符串 str1:%s\n", str1); printf("整数 num2:%d\n", num2); printf("字符串 str2:%s\n", str2); return 0; }
整数 num1:12345 字符串 str1:12345 整数 num2:-6789 字符串 str2:-6789
4.4 ltoa
函数
- 功能:将长整型转换为字符串,参数和用法与
itoa
类似- - 原型:
char* ltoa(long value, char* str, int base);
#include <stdio.h> #include <stdlib.h> int main() { // 定义整数 long num1 = 12345; long num2 = 987654321; // 使用ltoa将整数转换为字符串 char str1[20]; // 假设足够大以容纳转换后的字符串 char str2[20]; ltoa(num1, str1, 10); ltoa(num2, str2, 10); // 打印结果 printf("整数 num1:%ld\n", num1); printf("字符串 str1:%s\n", str1); printf("整数 num2:%ld\n", num2); printf("字符串 str2:%s\n", str2); return 0; }
整数 num1:12345 字符串 str1:12345 整数 num2:987654321 字符串 str2:987654321
4.5 ultoa
函数
- 功能:将无符号长整型转换为字符串,参数和用法与
itoa
类似 - 原型:
char* ultoa(unsigned long value, char* str, int base);
#include <stdio.h> #include <stdlib.h> int main() { // 定义无符号长整型数 unsigned long num1 = 12345; unsigned long num2 = 879631; // 定义存储转换后字符串的数组 char str1[20]; // 大小需要足够存储转换后的字符串 char str2[20]; // 使用 ultoa 将无符号长整型数转换为字符串 ultoa(num1, str1, 10); ultoa(num2, str2, 10); // 打印结果 printf("无符号长整型数 num1: %lu\n", num1); printf("字符串 str1: %s\n", str1); printf("无符号长整型数 num2: %lu\n", num2); printf("字符串 str2: %s\n", str2); return 0; }
String str1: 12345 Integer int1: 12345 String str2: 879631 Integer int2: 879631
4.5 strtol
函数
- 功能:将二进制字符串转换为整数,参数和用法与
itoa
类似 - 原型:
long int strtol(const char *str, char **endptr, int base);
#include <stdio.h> #include <stdlib.h> int main() { char binaryString[] = "110101"; // 二进制字符串 char *endptr; // 用于存储转换后的剩余部分的指针 // 使用 strtol 将二进制字符串转换为整数 long result = strtol(binaryString, &endptr, 2); // 检查转换是否成功 if (*endptr != '\0') { printf("转换失败,无效字符:%c\n", *endptr); } else { printf("转换成功,结果为:%ld\n", result); } return 0; }
转换成功,结果为:53
5 其他函数
5.1 qsort
函数
- 功能:用于对数组进行快速排序的函数
- 原型:
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
下面对函数的参数进行详解:
base
:指向要排序的数组的起始地址的指针。nmemb
:数组中元素的个数。size
:数组中每个元素的大小(以字节为单位)。compar
:比较函数的指针。这个函数用于定义数组元素之间的比较规则。它接受两个指向元素的指针,比较这两个元素的大小,并返回一个整数,表示它们的相对顺序。比较函数的返回值有三种情况:- 若返回值小于 0,则表示第一个元素要在第二个元素后面
- 若返回值等于 0,不进行操作
- 若返回值大于 0,则表示第一个元素要在第二个元素之前
qsort
函数使用快速排序算法,这是一种高效的排序算法,平均时间复杂度为 O(n log n)。排序是在原地进行的,不需要额外的辅助数组。
以下是一个简单的示例,演示如何使用 qsort
函数:
#include <stdio.h> #include <stdlib.h> // 比较函数 int compare(const void *a, const void *b) { return (*(int *)a - *(int *)b); } int main() { int arr[] = {5, 2, 9, 1, 5, 6}; size_t n = sizeof(arr) / sizeof(arr[0]); // 调用 qsort 函数进行排序 qsort(arr, n, sizeof(arr[0]), compare); // 输出排序后的数组 for (size_t i = 0; i < n; i++) { printf("%d ", arr[i]); } return 0; }
1 2 5 5 6 9
在这个例子中,
compare
函数用于比较整数,将数组元素按升序排序。qsort
函数将会根据compare
函数的定义对数组进行排序。在实际使用中,可以根据需要定义不同的比较函数来实现不同的排序规则。
compare 的示例
整型
int cmp_int(const void* e1, const void* e2) { return *(int*)e1 - *(int*)e2; }
浮点型
int cmp_float(const void* e1, const void* e2) { return (int)(*(float*)e1 - *(float*)e2); }
字符串
int cmp_str_size(const void* e1, const void* e2) { return strcmp((char*)e1,(char*)e2); }
字符串的长度
int cmp_str_len(const void* e1, const void* e2) { return strlen((char*)e1)-strlen((char*)e2); }
结构体
int cmp_by_age(const void*e1, const void*e2) { return (int)(((stu*)e1)->weight - ((stu*)e2)->weight); }
需要注意的是:返回结果一定要确保是整形,如果不是一定要强制类型转换成整形!
5.1 swab
函数
- 功能:在不同字节序之间交换数据
- 原型:
void swab(char *from,char *to,int n);
#include<stdio.h> #include<stdlib.h> #include<string.h> int main(void){ char suc[20]={"1234567890"}; char des[20]; swab(suc,des,strlen(suc)); printf("This is suc: %s\n",suc); printf("This is dest: %s\n",des); return 0; }
This is suc: 1234567890 This is dest: 2143658709
5.12bsearch
函数
- 功能:用于二分法搜索
- 原型:
void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
参数说明:
key
:要查找的元素的指针,即要在数组中查找的元素。base
:指向已排序数组的起始地址的指针。nmemb
:数组中元素的个数。size
:每个元素的大小(以字节为单位)。compar
:比较函数的指针,用于定义元素之间的比较规则。该函数应返回一个整数,表示两个元素的相对顺序。
bsearch
函数的返回值是一个指向匹配元素的指针,如果找到匹配的元素,则返回指向该元素的指针;如果没有找到匹配的元素,则返回NULL
。
比较函数compar
的原型如下:
int compar(const void *a, const void *b);
比较函数应该返回一个整数,其含义如下:
- 如果
a
小于b
,则返回负值。 - 如果
a
等于b
,则返回零。 - 如果
a
大于b
,则返回正值。
#include <stdio.h> #include <stdlib.h> // 比较函数,用于定义整数之间的比较规则 int compareIntegers(const void *a, const void *b) { return (*(int*)a - *(int*)b); } int main() { int arr[] = {1, 2, 4, 6, 8, 10, 12, 14, 16, 18}; int size = sizeof(arr) / sizeof(arr[0]); int key = 12; // 使用bsearch在已排序数组中查找元素 int *result = (int*)bsearch(&key, arr, size, sizeof(arr[0]), compareIntegers); if (result != NULL) { printf("元素 %d 找到在数组中的位置:%ld\n", key, result - arr); } else { printf("元素 %d 未找到\n", key); } return 0; }
元素 12 找到在数组中的位置:6
结语
<stdlib.h>
头文件提供了许多在 C 语言中常用的功能,从内存管理到随机数生成,再到字符串转换,都有涉及。熟练掌握这些函数的用法,有助于提高程序的效率和可维护性。
请记得在使用这些函数时要注意内存的分配和释放,以免造成内存泄漏和其他不稳定的行为。希望本博客对你理解和使用 <stdlib.h>
有所帮助。如有疑问或建议,欢迎留言讨论。