C 语言 <stdlib.h> 头文件详解

C 语言 stdlib.h 头文件详解

    • 1、引言
    • [2、 头文件概述](#2、 头文件概述)
    • [3、 内存分配与释放](#3、 内存分配与释放)
      • [3.1、 malloc 与 free](#3.1、 malloc 与 free)
      • [3.2、 calloc 与 realloc](#3.2、 calloc 与 realloc)
    • [4、 字符串与数值转换](#4、 字符串与数值转换)
      • [4.1、 基础转换示例](#4.1、 基础转换示例)
      • [4.2 、strtol 的进阶用法](#4.2 、strtol 的进阶用法)
    • [5、 随机数生成](#5、 随机数生成)
      • [5.1 、生成指定范围的随机数](#5.1 、生成指定范围的随机数)
    • [6、 排序与查找](#6、 排序与查找)
      • [6.1 、qsort 排序](#6.1 、qsort 排序)
      • [6.2、 bsearch 二分查找](#6.2、 bsearch 二分查找)
    • [7、 程序控制与环境交互](#7、 程序控制与环境交互)
      • [7.1、 程序终止](#7.1、 程序终止)
      • [7.2 、环境变量](#7.2 、环境变量)
      • [7.3、 执行系统命令](#7.3、 执行系统命令)
    • 8、整数除法与取余
    • [9、 常用宏与常量](#9、 常用宏与常量)
    • 10、总结
  • 二、代码示例

1、引言

在 C 语言的标准库中,<stdlib.h> 是一个极其重要且常用的头文件。它全称是 Standard Library(标准库),提供了内存分配、程序控制、类型转换、随机数生成、排序与查找等一系列基础而强大的功能。无论是初学者还是资深开发者,几乎每个 C 程序都会直接或间接地用到它。

2、 头文件概述

<stdlib.h> 是 C 标准库的一部分,定义了以下内容:

  • 类型 :如 size_t、div_t、ldiv_t 等。
  • 宏 :如 NULL、EXIT_SUCCESS、EXIT_FAILURE、RAND_MAX 等。
  • 函数:涵盖内存管理、字符串转换、随机数、排序查找、环境交互、程序终止等。

使用该头文件时,只需在源文件顶部包含:

c 复制代码
#include <stdlib.h>

3、 内存分配与释放

动态内存管理是 <stdlib.h> 最核心的功能之一,主要包含以下四个函数:

函数 功能
malloc(size_t size) 分配 size 字节的未初始化内存
calloc(size_t n, size_t size) 分配 n 个大小为 size 字节的连续内存,并初始化为 0
realloc(void *ptr, size_t size) 调整已分配内存块的大小
free(void *ptr) 释放之前分配的内存

3.1、 malloc 与 free

c 复制代码
#include <stdio.h>
#include <stdlib.h>

int main() {
    int *arr = (int *)malloc(5 * sizeof(int));
    if (arr == NULL) {
        fprintf(stderr, "内存分配失败\n");
        return EXIT_FAILURE;
    }

    for (int i = 0; i &lt; 5; i++) {
        arr[i] = i * i;
    }

    for (int i = 0; i &lt; 5; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    free(arr);
    return EXIT_SUCCESS;
}

注意事项:

  • malloc 返回 void *,使用时通常需要强制类型转换。
  • 分配失败时返回 NULL,务必检查。
  • 使用完毕后必须调用 free 释放,否则会造成内存泄漏。

3.2、 calloc 与 realloc

c 复制代码
#include <stdio.h>
#include <stdlib.h>

int main() {
    // calloc:分配并清零
    int *p = (int *)calloc(4, sizeof(int));
    if (p == NULL) return EXIT_FAILURE;

    for (int i = 0; i &lt; 4; i++) {
        printf("%d ", p[i]);  // 全部为 0
    }
    printf("\n");

    // realloc:扩容到 8 个 int
    int *q = (int *)realloc(p, 8 * sizeof(int));
    if (q == NULL) {
        free(p);
        return EXIT_FAILURE;
    }
    p = q;

    p[6] = 42;
    printf("p[6] = %d\n", p[6]);

    free(p);
    return EXIT_SUCCESS;
}

4、 字符串与数值转换

<stdlib.h> 提供了一组将字符串转换为数值的函数:

函数 功能
atoi(const char *str) 字符串转 int
atol(const char *str) 字符串转 long
atof(const char *str) 字符串转 double
strtol(const char *str, char **endptr, int base) 字符串转 long,支持指定进制
strtod(const char *str, char **endptr) 字符串转 double

4.1、 基础转换示例

c 复制代码
#include <stdio.h>
#include <stdlib.h>

int main() {
    const char *numStr = "12345";
    int num = atoi(numStr);
    printf("atoi(\"%s\") = %d\n", numStr, num);

    const char *floatStr = "3.14159";
    double pi = atof(floatStr);
    printf("atof(\"%s\") = %f\n", floatStr, pi);

    return EXIT_SUCCESS;
}

4.2 、strtol 的进阶用法

strtol 比 atoi 更安全,因为它能检测转换错误并支持进制:

c 复制代码
#include <stdio.h>
#include <stdlib.h>

int main() {
    const char *hexStr = "FF";
    char *endptr;

    long value = strtol(hexStr, &amp;endptr, 16);
    printf("strtol(\"%s\", base=16) = %ld\n", hexStr, value);

    if (*endptr != '\0') {
        printf("存在无法转换的字符: %s\n", endptr);
    }

    return EXIT_SUCCESS;
}

5、 随机数生成

<stdlib.h> 提供了伪随机数生成函数:

函数 功能
rand() 返回 0 到 RAND_MAX 之间的伪随机整数
srand(unsigned int seed) 设置随机数种子

5.1 、生成指定范围的随机数

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main() {
    // 用当前时间作为种子
    srand((unsigned int)time(NULL));

    // 生成 1 到 100 之间的随机数
    for (int i = 0; i &lt; 5; i++) {
        int r = rand() % 100 + 1;
        printf("%d ", r);
    }
    printf("\n");

    return EXIT_SUCCESS;
}

注意 :rand() % n 会产生轻微偏差,若对均匀性要求极高,可使用更精细的算法。

6、 排序与查找

<stdlib.h> 提供了通用的排序和二分查找函数,它们基于函数指针实现,适用于任意数据类型。

6.1 、qsort 排序

c 复制代码
#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, 7};
    int n = sizeof(arr) / sizeof(arr[0]);

    qsort(arr, n, sizeof(int), compare);

    for (int i = 0; i &lt; n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return EXIT_SUCCESS;
}

6.2、 bsearch 二分查找

c 复制代码
#include <stdio.h>
#include <stdlib.h>

int compare(const void *a, const void *b) {
    return (*(int *)a - *(int *)b);
}

int main() {
    int arr[] = {1, 3, 5, 7, 9};
    int n = sizeof(arr) / sizeof(arr[0]);
    int key = 7;

    int *found = (int *)bsearch(&amp;key, arr, n, sizeof(int), compare);

    if (found != NULL) {
        printf("找到元素: %d\n", *found);
    } else {
        printf("未找到元素\n");
    }

    return EXIT_SUCCESS;
}

注意 :bsearch 要求数组必须已按升序排序。

7、 程序控制与环境交互

7.1、 程序终止

函数 功能
exit(int status) 正常终止程序,刷新缓冲区
abort() 异常终止程序,不刷新缓冲区
atexit(void (*func)(void)) 注册程序退出时调用的函数
c 复制代码
#include <stdio.h>
#include <stdlib.h>

void cleanup() {
    printf("执行清理操作\n");
}

int main() {
    atexit(cleanup);
    printf("程序即将退出\n");
    return EXIT_SUCCESS;
}

7.2 、环境变量

c 复制代码
#include <stdio.h>
#include <stdlib.h>

int main() {
    const char *path = getenv("PATH");
    if (path != NULL) {
        printf("PATH = %s\n", path);
    } else {
        printf("未找到 PATH 环境变量\n");
    }

    return EXIT_SUCCESS;
}

7.3、 执行系统命令

c 复制代码
#include <stdlib.h>

int main() {
    int ret = system("echo Hello from system()");
    return ret;
}

8、整数除法与取余

<stdlib.h> 提供了 div 和 ldiv 函数,一次调用同时返回商和余数:

c 复制代码
#include <stdio.h>
#include <stdlib.h>

int main() {
    div_t result = div(17, 5);
    printf("商 = %d, 余数 = %d\n", result.quot, result.rem);

    return EXIT_SUCCESS;
}

9、 常用宏与常量

宏 含义
NULL 空指针常量
EXIT_SUCCESS 程序成功退出码(0)
EXIT_FAILURE 程序失败退出码(非 0)
RAND_MAX rand() 能返回的最大值

10、总结

<stdlib.h> 是 C 语言标准库中的核心头文件,涵盖了内存管理、类型转换、随机数、排序查找、程序控制等关键功能。熟练掌握这些函数,能够显著提升 C 程序的开发效率与健壮性。

在实际开发中,建议:

  • 使用 strtol 替代 atoi 以获得更好的错误检测。
  • 动态内存分配后务必检查返回值并及时释放。
  • 使用 qsort 和 bsearch 时,确保比较函数逻辑正确。
  • 合理使用 atexit 注册清理函数,避免资源泄漏。

二、代码示例

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <Windows.h>

// qsort 比较回调函数
int cmp_int(const void* a, const void* b)
{
    // 升序排序
    return *(const int*)a - *(const int*)b;
}

// bsearch 查找回调函数
int search_cmp(const void* key, const void* elem)
{
    return *(const int*)key - *(const int*)elem;
}

// atexit 注册的退出回调
void exit_callback(void)
{
    printf("[atexit] 程序即将退出\n");
}

int main(void)
{
    SetConsoleOutputCP(CP_UTF8);
    // ====================== 1. 内存分配 malloc / calloc / realloc / free ======================
    printf("===== 1. 动态内存分配 =====\n");
    // malloc:分配原始内存,不初始化
    int* p_malloc = (int*)malloc(4 * sizeof(int));
    if (p_malloc == NULL)
    {
        perror("malloc fail");
        return -1;
    }
    p_malloc[0] = 10;
    p_malloc[1] = 20;
    printf("malloc p_malloc[0] = %d\n", p_malloc[0]);

    // calloc:分配内存并全部置0
    int* p_calloc = (int*)calloc(4, sizeof(int));
    printf("calloc p_calloc[0] = %d\n", p_calloc[0]);

    // realloc 重新调整内存大小
    int* p_realloc = (int*)realloc(p_malloc, 8 * sizeof(int));
    if (p_realloc != NULL)
    {
        p_malloc = p_realloc;
    }
    free(p_malloc);
    free(p_calloc);
    printf("动态内存已释放\n\n");


    // ====================== 2. 随机数 rand / srand ======================
    printf("===== 2. rand srand 随机数 =====\n");
    srand((unsigned int)time(NULL)); // 设置随机种子,只用调用一次
    printf("3个随机数: %d, %d, %d\n", rand(), rand(), rand());
    // 获取 0~99 随机数
    int r = rand() % 100;
    printf("0~99随机数:%d\n\n", r);


    // ======================3. 字符串转数字 atoi / atol / atof ======================
    printf("=====3. atoi atol atof 字符串转数字(简易版)=====\n");
    const char* str_int = "1234";
    const char* str_long = "123456789";
    const char* str_double = "3.1415926";
    int i_val = atoi(str_int);
    long l_val = atol(str_long);
    double d_val = atof(str_double);
    printf("atoi: %s -> %d\n", str_int, i_val);
    printf("atol: %s -> %ld\n", str_long, l_val);
    printf("atof: %s -> %lf\n\n", str_double, d_val);


    // ======================4. strtol / strtoul / strtod 安全转换(推荐!) ======================
    printf("=====4. strtol strtoul strtod 安全字符串转换 =====\n");
    char* endptr;
    const char* num_str = "258abc";
    long s_l = strtol(num_str, &endptr, 10); //10进制
    printf("strtol 转换结果=%ld, 停止位置字符: %s\n", s_l, endptr);

    unsigned long s_ul = strtoul("666", NULL, 10);
    double s_d = strtod("9.876", NULL);
    printf("strtoul=%lu, strtod=%lf\n\n", s_ul, s_d);


    // ======================5. abs / labs 绝对值 ======================
    printf("=====5. abs labs 绝对值 =====\n");
    int a = -100;
    long la = -12345678L;
    printf("abs(-100)=%d\n", abs(a));
    printf("labs(-12345678)=%ld\n\n", labs(la));


    // ======================6. qsort 快速排序 ======================
    printf("=====6. qsort 快速排序 =====\n");
    int arr[] = { 9, 2, 7, 1, 5 };
    size_t arr_cnt = sizeof(arr) / sizeof(arr[0]);
    qsort(arr, arr_cnt, sizeof(int), cmp_int);
    printf("排序后数组:");
    for (size_t k = 0;k < arr_cnt;k++)
    {
        printf("%d ", arr[k]);
    }
    printf("\n\n");


    // ======================7. bsearch 二分查找【数组必须预先有序!】 ======================
    printf("=====7. bsearch 二分查找 =====\n");
    int key = 7;
    int* find_res = (int*)bsearch(&key, arr, arr_cnt, sizeof(int), search_cmp);
    if (find_res != NULL)
    {
        printf("找到数字 %d\n", *find_res);
    }
    else
    {
        printf("未找到\n");
    }
    printf("\n");


    // ======================8. atexit 注册退出回调函数 ======================
    printf("=====8. atexit 注册退出回调 =====\n");
    atexit(exit_callback);
    printf("main函数即将执行完毕,atexit回调会在return之前执行\n");

    // exit(0); // 强制退出程序,0正常,非0异常,会触发atexit
    return 0;
}

运行结果:

c 复制代码
===== 1. 动态内存分配 =====
malloc p_malloc[0] = 10
calloc p_calloc[0] = 0
动态内存已释放

===== 2. rand srand 随机数 =====
3个随机数: 30528, 14815, 12490
0~99随机数:16

=====3. atoi atol atof 字符串转数字(简易版)=====
atoi: 1234 -> 1234
atol: 123456789 -> 123456789
atof: 3.1415926 -> 3.141593

=====4. strtol strtoul strtod 安全字符串转换 =====
strtol 转换结果=258, 停止位置字符: abc
strtoul=666, strtod=9.876000

=====5. abs labs 绝对值 =====
abs(-100)=100
labs(-12345678)=12345678

=====6. qsort 快速排序 =====
排序后数组:1 2 5 7 9

=====7. bsearch 二分查找 =====
找到数字 7

=====8. atexit 注册退出回调 =====
main函数即将执行完毕,atexit回调会在return之前执行
[atexit] 程序即将退出

d:\user\01417804\桌面\CppProject\cppTest\x64\Debug\cppTest.exe (进程 16504)已退出,代码为 0 (0x0)。
要在调试停止时自动关闭控制台,请启用"工具"->"选项"->"调试"->"调试停止时自动关闭控制台"。
按任意键关闭此窗口. . .
相关推荐
Navigator_Z2 小时前
LeetCode //C - 1276. Number of Burgers with No Waste of Ingredients
c语言·算法·leetcode
wuminyu2 小时前
JVM虚拟线程的底层实现原理分析
java·linux·c语言·jvm·c++
番茄灭世神3 小时前
PN学堂GD32教程第11篇——I2C与EEPROM
c语言·stm32·单片机·嵌入式·gd32
阿钱真强道4 小时前
27 嵌入式操作系统 | C 网关:串口 ⇄ UDP 转发(先用 UDP 当上位机替身)
c语言·单片机·网关·udp·uloop
老王爱玩车5 小时前
深入理解指针6
c语言·开发语言·学习
苏辰澈5 小时前
C++自己的族谱规则:继承详解上
c语言·c++·visualstudio
Logic1017 小时前
C语言/数据结构字符串题解:按字符类型重排(数字→字母→符号)——三趟扫描稳定分区
c语言·数据结构·字符串·时间复杂度·计数排序·算法题·ascii
Logic10114 小时前
C语言/数据结构位运算题解:异或XOR找出学习计划中的“独特学习时间“——只出现一次的数字
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质
wuminyu14 小时前
C++协程实现接收端的零拷贝Buffer管理原理剖析
java·linux·c语言·jvm·c++