Linux 版 (精华区)
发信人: howdoit (第一个角球), 信区: Linux
标 题: Linux标准C库第五部分:<stdlib.h>
发信站: 哈工大紫丁香 (Thu May 20 08:51:58 1999), 转信
"Linux公报...让Linux更富魅力!"
Linux标准C库
第五部分: <stdlib.h>
By James M. Rogers 帆译
上一期中的文章是关于<ctype.h>字符处理的。本期将介绍
<stdlib.h>,它包含很多小的部分,有:整数计算,排序,查找,随
机数,字符串到整数的转换,多字节字符的转换,内存分配和环境函
数。因为这个库包含太多小而重要的部分,我想逐一的讨论。因为这
些函数的功能太分散,所以不能在一个例子中把它们介绍全,我会在
每个小部分后给出一个例子。
我假设这部分的读者有C编程的知识。我不对本文中的信息做任何
担保。
象往常一样,如果你在本文中发现任何错误,请告诉我,我将在
以后的文档中更正。以前文章的勘误请看本文最后的勘误一节。
整数计算
#include <stdlib.h>
int abs(int x);
div_t div(int numerator, int denominator);
long int labs(long int x);
ldiv_t ldiv(long int numerator, long int denominator);
int x
int numerator
int denominator
long int型和三个int型一样长。 //?
abs 返回参数的绝对值。
div 返回一个包含商和余数的数据结构。
labs 是abs的long int版本
ldiv 是div的long int版本
整数运算是用来处理整数的,不处理分数。这是四年级数学。分子除
以分母,得商,剩下的部分是余数。div_t 和 ldiv_t 结构用来保存
分子和分母。这两个结构如下所示:
struct div_t {
int quot;
int rem;
}
struct ldiv_t {
long int quot;
long int rem;
}
这些类型已经在<stdlib.h>中定义。这个例子显示了使用这四个函数
的一些方法。
字符串到数字的转换
#include <stdlib.h>
double atof(const char *string);
int atoi(const char *string);
long int atol(const char *string);
double strtod(const char *string, char **endptr);
long int strtol(const char *string, char **endptr, int base);
unsigned long int strtoul(const char *string, char **endptr, int
base);
const char *string
char **endptr
int base
atof 把acsii码转换成浮点数
atoi 把acsii码转换成整数
atol 把acsii码转换成长整数
strtod 把字符串转换成double型
strtol 把字符串转换成long型,而且可以转换除了10进制以外的其他
进制数
strtoul 和strtol一样,但它返回unsigned long
如果你从用户的输入读入一个数字,可能就要用这些函数把数字
'1','2','3'转换成数123。从数字到字符串最简单的转换方法是用
sprintf()函数。
这个程序演示了上面的这些函数的用法。
搜索和排序
#include <stdlib.h>
void qsort(void *base, size_t num_of_objs, size_t size_of_obj,
int (*compar)(const void *, const void *));
void bsearch(const void *key, void *base, size_t num_of_objs,
size_t size_of_obj, int (*compar)(const void *, const void *));
void *base
size_t num_of_objs
size_t size_of_obj
const void *
const void *key
qsort 使用你自己写的一个比较函数来排序一个数组。
bsearch 则使用一个你自己写的比较函数来在一个已排序的数组中进行
搜索
你不用自己来写排序算法,使用这些函数你可以对内存数组个进行排
序和搜索。
很重要的一点是在搜索以前,必须先给数组排序。
这个例子演示了排序和搜索,为了生成要排序的数字,我把这个例子
和产生随机数的例子放在了一起。我用一系列的随机数字初始化一个址椤H缓笏
阉000是否是不是在这个表里。最后把排序过的数组打印出来。
内存分配
#include <stdlib.h>
void *calloc(size_t num_of_objs, size_t size_of_objs);
void free(void *pointer_to_obj);
void *malloc(size_t size_of_object);
void *realloc(void *pointer_to_obj, size_t size_of_obj);
size_t num_of_objs
size_t size_of_objs
void *pointer_to_obj
free 释放以前分配的内存块。如果试图free一块内存两次,则会core
dump。
malloc 分配指定字节数的一块内存,并返回指向它的指针。
calloc 分配一个数组,返回指向数组的指针。
realloc 改变内存块的大小。你可以按你的需要来扩大或缩小内存块
的大小。注意,试图存取你已经分配过的内存以外的空间将会导致
core dump
运行时的内存分配技术允许你的程序仅仅使用程序运行所需的内
存大小。如果你在运行时要求分配内存,不用改变值并重新编译它。
当运行时数组的平均大小不大的时候,也不需要把它设的尽可能大,
可以在需要的时候动态扩展它。
这样使用内存的一个危险是在一个复杂的程序里,很容易在使用
完以后忘掉释放它。这样的“内存泄露”就会导致你的程序使用掉系
统中的所有的可用内存,从而使系统dump。不要认为内存分配总可以
成功,这一点很重要。试图使用一个不属于你应用程序的内存的指针
会导致core dump。更严重的问题是当指针覆盖了你自己程序的内存,
这会导致你的程序非常严重的错误,而且很难找到错误在哪里?
我写了两个不同的例子来演示这些函数的差别。
第一个例子是一个堆栈程序,该程序为push和pop堆栈分配和释放内
存。
第二个例子把某个文件读入内存,然后按它的大小重新分配内存。我
把调试语句留在了里面,这样你可以看到程序仅在需要的更多内存的
时候重新分配。
环境
#include <stdlib.h>
void abort ( void );
int atexit ( void ( *func )( void ) );
void exit ( int status);
char *getenv( const char *string);
int setenv ( const char *name, const char *value, int overwrite
);
int unsetenv ( const char *name, const char *value, int
overwrite );
int system ( const char *string );
void
void (*func)(void)
int status
const char *string
const char *name
const char *value
int overwrite
abort 会使得一个SIGABORT信号发到你的程序。除非你的程序处理了
它,否则会退出并带一个abort错误。
atexit 允许你的程序在退出的时候执行一个函数集。你可以堆叠相当
多的函数,好象最多可以到32个。
exit 函数用来退出程序,并带一个你指定的整数返回值。
getenv 返回指定的环境变量的值,如果该环境变量没被设置,它会返
回NULL。
setenv 给一个指定的环境变量设置一个特定的值。如果发生错误,返
回-1
unsetenv 会取消一个指定的变量
system 用来执行一个指定的命令字符串,并返回该命令的返回值。
这些函数允许你和运行程序的UNIX环境相交互、设置程序退出的返回
值、从环境变量中读取数据以及从C程序里运行命令。
这个例子演示如何读环境变量,和设置变量的两个方法。不设置
TESTING变量运行它,再"export TESTING=anything"来设置上TESTING
变量,再运行程序。你会注意到这两种方法的不同。另外注意一下
atexit()函数的调用顺序,和这些退出函数它们在程序退出的时候被
调用的顺序。在exit前面插入一个abort()函数调用,然后重新执行程
序,当abort调用的时候,atexit()设置的函数不会被调用。
随机数
#include <stdlib.h>
int rand(void);
void srand(unsigned int seed);
void
unsigned int seed
rand 返回一个从0到RAND_MAX中的一个随机数。
seed 开始一个新的伪随机数序列。
rand函数在第一次调用的时候把随机数种子设置成1,除非你把它设置
成其他的。如果你每次把种子设成同一个值,那么从rand产生的随机
数序列是一样的。要得到最接近真实的随机数,你应该把种子设置的
尽量不重复。这个例子中我使用time()函数来做到这一点。
这个例子是和排序与搜索的例子一起写的。
多字节转换
#include <stdlib.h>
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 wchar);
size_t mbstowcs(wchar_t *pwcs, const char *s, size_t n);
size_t mbstowcs(char *s, wchar_t *pwcs, size_t n);
参考书目:
The ANSI C Programming Language, Second Edition, Brian W.
Kernighan, Dennis M. Ritchie, Printice Hall Software Series,
1988
The Standard C Library, P. J. Plauger, Printice Hall P T R,
1992
The Standard C Library, Parts 1, 2, and 3, Chuck Allison,
C/C++ Users Journal, January, February, March 1995
STDLIB(3), BSD MANPAGE, Linux Programmer's Manual, 29
November 1993
以前的文章
The Standard C Library for Linux, stdio.h, James M. Rogers,
January 1998
The Standard C Library for Linux, stdio.h, James M. Rogers,
July 1998
The Standard C Library for Linux, stdio.h, James M. Rogers,
August 1998
The Standard C Library for Linux, ctype.h, James M. Rogers,
March 1999
版权所有 (C) 1999 NJLUG
出版于第39期《Linux公报》1999年4月 中文版第六期
--
☆ 来源:.哈工大紫丁香 bbs.hit.edu.cn.[FROM: bin@mtlab.hit.edu.cn]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:3.842毫秒