ANSI C标准库中包括了各种类型的实用工具函数,它们都在stdlib.h中定义,本文就介绍该头文件。

1. 类型

stdlib.h中定义了如下一些类型:

  • size_t :sizeof运算符返回的无符号整数类型
  • wchar_t :用来表示宽字符的整数类型
  • div_t :div( )函数返回的结构类型,它包含quot和rem两个成员,两个成员都为int类型
  • ldiv_t :ldiv( )函数返回的结构类型,它包含quot和rem两个成员,两个成员都为long类型
  • lldiv_t :lldiv( )函数返回的结构类型,它包含quot和rem两个成员,两个成员都为long long类型(C99)
typedef struct
{
int quot;           /* Quotient.  */
int rem;            /* Remainder.  */
} div_t;

typedef struct
{
long int quot;      /* Quotient.  */
long int rem;       /* Remainder.  */
} ldiv_t;

typedef struct
{
long long int quot;     /* Quotient.  */
long long int rem;      /* Remainder.  */
} lldiv_t;

2. 常量

stdlib.h中定义了如下常量:

  • NULL :空指针(等于0)
  • EXIT_FAILURE :可以作为exit( )的参数类型,表示没有成功的执行一个程序,一般定义为:#define EXIT_FAILURE    1   /* Failing exit status.  */
  • EXIT_SUCCESS :可以作为exit( )的参数类型,表示成功的执行一个程序,一般定义为:#define EXIT_SUCCESS    0   /* Successful exit status.  */
  • RAND_MAX :rand( )返回的最大值(一个整数),一般定义为:#define RAND_MAX    2147483647
  • MB_CUR_MAX :对应于当前场景的扩展字符集中的多字节字符的最大字节数

3. 函数

3.1 字符串转换为整数/浮点数的函数族

函数原型:

/* 第一组 */
int atoi(const char *nptr);
long atol(const char *nptr);
long long atoll(const char *nptr);
long long atoq(const char *nptr);    
double atof(const char *nptr);

/* 第二组 */        
double strtod(const char *nptr, char **endptr);
float strtof(const char *nptr, char **endptr);
long double strtold(const char *nptr, char **endptr);

/* 第三组 */
long int strtol(const char *nptr, char **endptr, int base);
long long int strtoll(const char *nptr, char **endptr, int base);
unsigned long int strtoul(const char *nptr, char **endptr, int base);
unsigned long long int strtoull(const char *nptr, char **endptr, int base);

函数功能:

第一组:atoi 把nptr指向的字符串的开始部分转换为int类型的值;在碰到第一个不是数字的字符时结束转换;跳过开始的空格;如果没有数字则返回0.atoi函数相当于strtol(nptr, NULL, 10); atof函数相当于strtod(nptr, NULL) 。该组的其他函数与aoti功能相似,只不过将字符串转化为他们的返回值类型。需要注意的是该组函数都没有错误检测功能。

第二组:strtod 把nptr指向的字符串的开始部分转换为double类型的值;在碰到第一个不是数字的字符时结束转换;跳过开始的空格;如果没有数字则返回0;如果转换成功,把数字之后第一个字符的地址赋给endptr;如果转换失败,把npt赋给endptr。其他两个函数与strtod函数功能类似,只不过转换类型不同。

第三组:第三组的函数与第二组相比,多了一个参数base,这个参数用来表示字符串中的数字是以哪一种进制的数来表示的,比如base取10则代表字符串中的数字是以十进制表示的。其他与第二组函数相同。

3.2 rand && srand

函数原型:

int rand(void);
void srand(unsigned int seed);

函数功能:

rand( )函数用于返回[ 0, RAND_MAX ]范围内的一个伪随机数。如果在一个程序中重复调用rand将生成不同的伪随机数,那如何让每次生成的随机数一样呢?那就是在调用rand之前调用srand,且srand使用相同的种子。

 3.3 内存管理相关函数族

函数原型:

void *malloc(size_t size);
void free(void *ptr);
void *calloc(size_t nmemb, size_t size);
void *realloc(void *ptr, size_t size);

 函数功能:

  • malloc 在内存中分配一块大小为size字节的未初始化的块,如果成功函数返回申请的地址,否则返回NULL。
  • free释放ptr指向的内存;ptr应该是以前对calloc( )、malloc( )或realloc( )的调用返回的值;ptr也可以是空指针,这种情况下不进行任何动作;如果是其他的指针值,则结果是未定义的。
  • calloc 为具有nmemb个成员的数组分配空间,其中每个元素的大小都为size字节;且该块内存会被初始化为0;函数成功时返回内存地址,失败返回NULL。
  • realloc 把ptr指向的内存块大小改变为size字节:从内存块开始一直到min(old_size, new_size)处的内存内容都不会被改变;函数返回新的内存块的位置,它可能被移动过。如果空间不能被重分配,函数返回NULL且不改变旧的内存块的值;如果ptr为空,就相当于调用了参数为size的malloc( );如果size为0而ptr不为空,则相当于调用参数为ptr的free( )。

3.4 程序退出函数族

函数原型:

void abort(void);
void exit(int status);
void _Exit(int status);
int atexit(void (*function)(void));

 函数功能:

  • abort 该函数会执行raise(SIGABRT),除非信号SIGABRT被捕获而且对应的信号处理函数没有返回,否则该函数会使程序异常终止,所有打开的I/O流和临时文件将被关闭;该函数无返回值。
  • exit 该函数使程序正常退出:首先调用由atexit( )或on_exit( )注册的函数,然后刷新所有打开的输出流,关闭所有的I/O流,关闭所有由tmpfile( )创建的文件,然后把控制权返回到主机环境中。如果status为0或者EXIT_SUCCESS,就向主机环境返回一个实现定义的表示成功结束的值;如果status为EXIT_FAILURE,就向主机环境返回一个实现定义表示不成功结束的值;其他status的值的效果要由实现来定义。并且 status & 0377的值会返回给它的父进程。
  • _Exit 该函数和<unistd.h>中定义的_exit函数一样,它们类似于exit( ),只是不调用atexit( )注册的函数,也不调用signal( )注册的信号处理函数,并且对已打开的流的处理方法将由实现定义。_Exit为C99中新增加的函数。
  • atexit 注册func指向的函数,使他在程序正常结束时被调用;实现应该至少支持注册32个函数,按照他们注册的相反顺序进行调用,每个函数只调用依次;如果注册成功,函数返回0,否则返回一个非0值。

3.5 getenv

函数原型:

char *getenv(const char *name);

 函数功能:

返回一个纸箱字符串的指针,这个字符串表示有name指向的环境变量的值;如果没有相匹配的环境变量则返回NULL。

3.6 system

函数原型:

int system(const char *command);

 函数功能:

把command指向的字符串传递给像DOS或UNIX这样的命令处理器(比如Linux下的Shell)执行的主机环境;如果command是NULL,当命令处理器可用时返回非0,否则返回0;如果str不为NULL,则返回值要依赖于实现。注意在command执行期间,SIGCHLD信号将被阻塞(blocked),SIGINT和SIGQUIT将被忽略(ignored)。

3.7 qsort

函数原型:

void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));

 函数功能:

把base指向的数组按照compar指向的函数提供的顺序进行排序,这个数组具有nmemb个大小为size字节的元素;如果第一个参数指向的对象小于第二个参数指向的对象比较函数返回一个小于0的值,相等返回0,第一个参数指向的对象大于第二个参数指向的对象比较函数返回一个大于0的值。

看下面一个Linux man文档里面的例子:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static int
cmpstringp(const void *p1, const void *p2)
{
   /* The actual arguments to this function are "pointers to
      pointers to char", but strcmp(3) arguments are "pointers
      to char", hence the following cast plus dereference */

   return strcmp(* (char * const *) p1, * (char * const *) p2);
}

int
main(int argc, char *argv[])
{
   int j;

   if (argc < 2) {
    fprintf(stderr, "Usage: %s <string>...n", argv[0]);
    exit(EXIT_FAILURE);
   }

   qsort(&argv[1], argc - 1, sizeof(char *), cmpstringp);

   for (j = 1; j < argc; j++)
       puts(argv[j]);
   exit(EXIT_SUCCESS);
}

函数编译运行结果:

allan@ubuntu:workspace$ ./a.out Jan Feb Mar Apri May Jun July Aug Sep Oct Nov Dec
Apri
Aug
Dec
Feb
Jan
July
Jun
Mar
May
Nov
Oct
Sep

3.8 bsearch

函数原型:

void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));

 函数功能:

该函数搜索由base指向的具有nmemb个大小为size的元素的数组,在其中寻找与key指向的对象相匹配的元素。元素的比较由compar指向的比较函数执行;如果key指向的对象小于某个数组元素,比较函数就返回一个小于0的值,如果相等返回0,如果key对象比数组元素大就返回一个大于0的值。需要注意的是base指向的数组在比较函数的含义上面必须是一个递增的数组。bsearch函数返回指向匹配元素的指针:如果没有匹配的元素,函数返回NULL,如果有多个元素与key对象匹配,则返回哪个是未指定的。

看Linux man文档中的一个例子:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct mi {
   int nr;
   char *name;
} months[] = {
   { 1, "jan" }, { 2, "feb" }, { 3, "mar" }, { 4, "apr" },
   { 5, "may" }, { 6, "jun" }, { 7, "jul" }, { 8, "aug" },
   { 9, "sep" }, {10, "oct" }, {11, "nov" }, {12, "dec" }
};

#define nr_of_months (sizeof(months)/sizeof(months[0]))

static int
compmi(const void *m1, const void *m2)
{
   struct mi *mi1 = (struct mi *) m1;
   struct mi *mi2 = (struct mi *) m2;
   return strcmp(mi1->name, mi2->name);
}

int main(int argc, char **argv)
{
   int i;

   qsort(months, nr_of_months, sizeof(struct mi), compmi);
   for (i = 1; i < argc; i++) {
       struct mi key, *res;
       key.name = argv[i];
       res = bsearch(&key, months, nr_of_months,
                     sizeof(struct mi), compmi);
       if (res == NULL)
           printf("'%s': unknown monthn", argv[i]);
       else
           printf("%s: month #%dn", res->name, res->nr);
   }
   exit(EXIT_SUCCESS);
}

编译后的运行结果:

allan@ubuntu:workspace$ ./a.out jan
jan: month #1
allan@ubuntu:workspace$ ./a.out nov
nov: month #11
allan@ubuntu:workspace$ ./a.out nov  jan
nov: month #11
jan: month #1

3.9 绝对值函数族

函数原型:

int abs(int j);
long int labs(long int j);
long long int llabs(long long int j)

 函数功能:

  • abs 返回j的绝对值;如果j是一个负数并且没有与它对应的正数,那么返回值是未定义的,比如两个数都用补码表示,而j为INT_MIN时就会发生这种情况。
  • labs 返回j的绝对值;如果j是一个负数并且没有与它对应的正数,那么返回值是未定义的,比如两个数都用补码表示,而j为LONG_MIN时就会发生这种情况。
  • llabs 返回j的绝对值;如果j是一个负数并且没有与它对应的正数,那么返回值是未定义的,比如两个数都用补码表示,而j为LONG_LONG_MIN时就会发生这种情况(C99)。

3.10 除法运算函数族

函数原型:

div_t div(int numerator, int denominator);
ldiv_t ldiv(long numerator, long denominator);
lldiv_t lldiv(long long numerator, long long denominator);

 函数功能:

  • div 计算numerator除以denominator的商和余数,把商放在一个div_t结构的quot成员中,把余数放在他的rem成员中;对于不精确的除法,商是大小小于算术商而距离算术商最近的整数(也就是说,趋零截尾)。
  • ldiv 计算numerator除以denominator的商和余数,把商放在一个ldiv_t结构的quot成员中,把余数放在他的rem成员中;对于不精确的除法,商是大小小于算术商而距离算术商最近的整数(也就是说,趋零截尾)。
  • lldiv 计算numerator除以denominator的商和余数,把商放在一个lldiv_t结构的quot成员中,把余数放在他的rem成员中;对于不精确的除法,商是大小小于算术商而距离算术商最近的整数(也就是说,趋零截尾)。

3.11 多字节字符处理函数族

函数原型:

int mblen(const char *s, size_t n);
int mbtowc(wchar_t *pwc, const char *s, size_t n);
int wctomb(char *s, wchar_t wc);
size_t mbstowcs(wchar_t *dest, const char *src, size_t n);
size_t wcstombs(char *dest, const wchar_t *src, size_t n);

 函数功能:

  • mblen 返回组成s指向的多字节字符的字节数(最大为n);如果s指向空字符,返回0;如果s没有指向一个多字节字符返回-1;如果s为NULL,那么如果多字节字符时根据状态进行编码则返回非0值,否则返回0.
  • mbtowc 如果s不为空,就确定组成s指向的多字节字符的字节数(最大为n),并确定这个多字节字符的wchar_t编码类型;如果pwc不是空指针,就把这个编码类型赋值给pw;返回以mblen(s,n)相同的值。
  • wctomb 把wc中的字符编码转换为对应的多字节字符表示,并把它存储在s指向的数组中(除非s是空指针)。如果s不是空指针,那么如果wc不对应一个合法的多字节字符,返回-1;如果wc合法,就返回组成多字节字符的字节数。如果s是空指针,那么如果多字节字符是根据状态进行编码就返回非0值,否则返回0.
  • mbstowcs 把src指向的多字节字符数组转换为一个存储在从dest开始的位置中的宽字符编码数组;转换过程在到达dest的第n个元素或者碰到src数组中的空字节时停止;如果碰到一个非法的多字节字符就返回(size_t)(-1),否则返回填充了的数组元素个数(不包括结束符,如果有的话)。
  • wcstombs 把存储在src指向的数组中的宽字符编码序列转换为一个多字节字符序列,并把它复制到dest指向的位置。在存储了n个字节或者碰到空字符是停止转换。如果碰到一个非法的宽字符编码,就返回(size_t)(-1),否则返回填充的数组字节数(不包括结束符,如果有的话)。

多字节字符系列的函数感觉不太常用。