本篇介绍若干经常使用的标准C函数的使用方法,主要介绍stdio(标准输入输出)、math(数字函数库)、time(时间函数库)、stdlib(标准函数库)string(标准字符串函数)等。

最后更新 2015-03-17

权利声明:作者拥有本书的所有权利。作者授权不论什么人都能够自由转载本站点发布的内容,但转载时必须遵守下面限制: ①转载时必须全文转载,不得有不论什么改动,必须包括“权利声明”和“官网地址” ② 仅限于网络转载,即终于结果发布于网络上。凡是不遵守以上两条的转载行为视为侵权行为。除非本人同意,不论什么人不得将本站点内容内容用于不论什么的其它用途。 

官网地址: http://www.afanihao.cn/  留言请到http://www.afanihao.cn/kbase/

1.1         stdio.h

标准输入/输出函数,stdio即standard input/output。当中文件操作相关API在单独一章中介绍。

#include <stdio.h>

char getchar(void);  // 控制台输入一个字符

int putchar(int c);  // 控制台输出一个字符

char *gets(char *s);  // 控制台输入一个字符串

int puts(const char *s); // 控制台输出一个字符串

int printf(const char *format, ...);  // 控制台格式化输出

int scanf(const char *format, ...);  // 控制台格式化输入

int sprintf(char *s, const char *format, ...); // 字符串格式化输出

int sscanf(const char *s, const char *format, ...); // 字符串格式化输入

1.1.4       sprintf与sscanf

适用于string版本号的格式化输入/输出。其目标不是控制台,而是一个字符串。这两个函数很实用。

用sprintf格式化一个字符串,比如,

char  buf [256];
sprintf (buf, "Name: %s, Age: %d, Height: %.2f \n", “LiMing", 30, 1.68 );

此代码将目标buf格式化为:  Name: LiMing, Age 30, Height: 1.68

用sscanf从一个具有格式的字符串中提取固定字段,和scanf的使用方法类似,要求在格式上要严格匹配。

下面代码从字符中提供取年月日的值。

char*  src = "2014-12-11";
int year, month, day;
int n = sscanf ( src,
"%d-%d-%d",
&year, &month, &day);
if( n == 3)
{
// 成功提取了全部字段
}

1.2         math.h

提供了一系列数学相关的函数,如三角函数、指数/对数、幂/根号等。

#include <math.h>

double abs(double x);  // 取绝对值

double cos(double x);  // 余弦cos, 參数是弧度值

double sin(double x);   // 正弦sin, 參数是弧度值

double tan(double x);  // 正切 tan, 參数是弧度值

double ceil(double x); // 向上取整, 即不小于x的最小整数

double floor(double x); // 向下取整, 即不大于x的最大整数

double exp(double x); // 求ex

double log(double x); // ln(x), 以e为底的对数

double log10(double x); // lg(x), 以10为底的对数

double pow(double x, double y); // 求幂xy

double sqrt(double x); // 求平方根  x1/2

须要补充说明的是,这里所列的差点儿全部函数都至少有2个版本号,各自是double型和float型參数。比如,

double sqrt(double x);
float sqrt(float x);

下面代码编译错误。

double result = sqrt (16);  // 编译错误

为什么会有编译错误呢?由于字面常量16是int型,在匹配函数时,sqrt(float)与sqrt(double)均被匹配,int能够隐式转换成float和double。必需要显示把參数强转为double或float。

假设要对一个整数调用sqrt函数,那么就必须显式的强转成double或float。比如,

double result = sqrt ((double)16);  // OK

float result = sqrt ((float)16); // OK

1.2.1       abs求绝对值

比如 ,

double  a =  abs ( -12.34);

1.2.2       cos/sin/tan三角函数

其单位都是弧度值。

比如,

#define  PI  3.1415926535898
double ret = sin ( PI / 2); // sin (pi/2)结果应为1

1.2.3        ceil /floor取整

用于向上/向下取整。

比如,

       double  ci =  ceil ( 12.87 ); // +13
double fi = floor(12.87); // +12
ci = ceil ( -12.87 ); // -12
fi = floor( -12.87); // -13

1.2.4       exp / log / log10 / pow / sqrt指数/对数/幂/平方根

点击查看此节内容,第16章

1.3         time.h

time.h中提供了时间/日期相关的函数。这里仅列出经常使用的几个函数。

#include <time.h>

struct tm *localtime(const time_t *tod); // 当“秒值”转成“年月日时分秒”

time_t mktime(struct tm *tptr);  // 将“年月日时分秒”转成“秒值”

time_t time(time_t *tod); // 取得当前时间

当中。须要介绍time_t和struct tm这两个类型。

1.3.1       time_t

time_t是一个typedef的类型,眼下在各种操作系统上time_t类型都是一个整数类型。差点儿相同就是

typedef long time_t;

这样的类似的定义,在各种场合都能够觉得它是int型。当然,保险起见也能够显式的强转一下。

它的单位是秒。

time_t  start = 1000;
time_t end = 1020;
printf("time eclipse: %d seconds !\n", (int)(end - start));

1.3.2       struct tm

tm是一个结构。它的定义是,

struct tm

{

int tm_sec;     /* seconds after the minute - [0,59] */

int tm_min;     /* minutes after the hour - [0,59] */

int tm_hour;    /* hours since midnight - [0,23] */

int tm_mday;    /* day of the month - [1,31] */

int tm_mon;     /* months since January - [0,11] */

int tm_year;    /* years since 1900 */

int tm_wday;    /* days since Sunday - [0,6] */

int tm_yday;    /* days since January 1 - [0,365] */

};

它用于表示日期/时间,有几个字段组成:年,月。日,时。分,秒,weekday和yearday。当中,

年:从1900開始算,tm_year = 114表示年份 1900 + 114 = 2014

月:范围是[0,11], tm_mon = 11表示月份 12

日:范围是[1,31], tm_mday = 24表示该月的第24天

时: 范围是[0,23],tm_hour = 13表示下午13时

分: 范围是[0,59], tm_min = 40表示第40分钟

秒:范围是[0,59], tm_sec = 40表示第40秒钟

tm_wday: 范围是[0,6],星期日是0,星期一是1。... 。星期六是6

tm_yday: 范围是[0,365]。tm_yday=299,表示当年的第300天

当tm_min和tm_sec都为0时。表示整点时间。

如12:00:00。

比如,2014-12-11 11:47:12这个时间能够用以下的代码赋值:

tm info;
info.tm_year = 2014 - 1900; // 2014年
info.tm_mon = 12 - 1; // 12月
info.tm_mday = 11; // 11日
info.tm_hour = 11; // 11时
info.tm_min = 47; // 47分
info.tm_sec = 12; // 12分

1.3.3       time取得系统当前时间

time函数能够取得系统当前时间,返回值是一个秒值。比如,

time_t  now = time (NULL);

为什么一个整数秒值能够表示当前的时间呢?是这么规定的,time函数返回的是自1970-1-1 00:00:00这个时间点開始至当前时刻的时间差。它是一个比較大的整数。比如1418270153表示的是2014-12-11 11:55:53这个时刻。

利用time函数时能够计算程序执行了多少时间,如以下的代码:

time_t  start = time (NULL);
... DoSomething ...
time_t end = time (NULL);
printf("Time cost : %d seconds", end - start );

当然这个DoSomething要执行相当时间才行,由于time的粒度较大,返回是秒值。假设你的DoSomething仅仅耗费了几毫秒的话。那么用time根本无法衡量。只是,能够成倍的量化一下,比較。将DoSomething连续运动10000次。看须要的总时间,然后再平均一下得出单次须要的时间。

time_t  start = time (NULL);
for( int i=0; i< 10000; i++)
{
... DoSomething ...
}
time_t end = time (NULL);
int avg = (end - start ) / 10000;

1.3.4       localtime()得到年月日时分秒

尽管用一个time_t整数来表示当前系统时间是比較方便的,但有时候还是希望能转化成年月日时分秒的形式来显示。毕竟肉眼无法直接看一个time_t值究竟是哪一个日期。

localtime函数能够将time_t所表示的时间转化成年月日时分秒,比如,

time_t t = time(NULL);
tm info = *localtime(&t);
printf("%04d-%2d-%02d %02d:%02d:%02d \n",
info.tm_year + 1900,
info.tm_mon + 1,
info.tm_mday,
info.tm_hour,
info.tm_min,
info.tm_sec);

localtime的返回值是tm*类型,应该用一个tm变量将内容保存起来。

其实,用time_t来记录时间更方便,仅仅用一个整数(占4个字节)就表达了日期和时间信息。在保存和传输的时候,应该尽量用time_t类型。仅仅是在终于显示的时候,用localtime转成人类易读的yyyy-mm-dd HH:MM:SS格式。

1.3.5       mktime构造时间

当已知了年月日时分秒信息,能够用mktime换算成time_t值。比如,把2014-12-11 11:47:12转成time_t值。

点击查看此节内容,第16章

1.4         stdlib.h

这一节将介绍stdlib.h里提供的API,以下列表当中基本的几个函数:

#include <stdlib.h>

double atof(const char *s);

int atoi(const char *s);

int rand(void);

void srand(unsigned int seed);

int system(const char *s);

1.4.1       atoi / atof 字符串转成数字

比如。

int  n  = atoi("1280");
double f = atof("12.80");

事实上全然能够用sscanf来完毕同样的事情,比如。

int n;
double f;
sscanf("1280", "%d", &n);
sscanf("12.80", "%f", &f);

相比之下。使用atoi和atof更简洁一些。

1.4.2        rand / srand 随机数生成

在抽签、抽奖等涉及“随机事件”的应用场景中,须要随机数生成函数。由于计算机中并没有随机性和偶然性,想制造一个随机数实际上是一件比較困难的事情。要真正随机的数字。须要购置在很昂贵的硬件,这些硬件利用某些自然科学的规则来生成随机数,由于价格昂贵。所以专业的随机数生成器仅仅用于专业用途。

我们这里介绍的适用普通PC机可以胜任的“伪随机数”生成函数,可以生成近似随机的数据就行了。

rand函数用于生成随机数,该函数返回一个整数。调用下面代码測试一下:

for(int i=0; i<10; i++)
{
printf("%d \n", rand());
}

控制台输出了10个全然没有规律的数字,由于全然无规律可循,所以称它为随机数。这里为了显示方便,仅仅生成了10个随机数,实际上能够改成1000次、10000次试试,会发现它确实是杂乱无章、全然没有规律的出现的。

那么为什么说它是“伪随机数”呢?说明它没有真正的实现“随机”。

能够这么验证一下。把同样的程序重复执行数次。会发现每次程序执行输出的结果都是同样的一个序列的数字。

比如,第一次执行程序的时候输出13435 31833 5075 19863 30565 11677 1339 4096 31105 9088等10个随机数。当关闭程序再次执行时。输出的10个随机数还是这10个数。

为了解决问题。stdlib.h里提供了srand函数。srand函数用于为程序设置一个种子(seed),当种子不同一时候。程序产生的随机数序列也不同。srand仅仅须要在程序開始时设置一次,比如。能够在main()函数開始时执行一次。种子怎么定呢?要保证程序每次执行时,这个种子的值不同,一般来说是取系统时间来作为种子的。

void main()
{
srand (time (NULL));
... do something else ...
}

每次程序执行时。time(NULL)返回的时间是不同的,于是srand每次都是使用了不同的种子。在程序中再调用rand()来生成随机数时,会发现每次程序执行生成的随机数序列是不同的。

在实际应用中怎样使用rand函数呢?比如。有一种彩票叫“七星彩”,每次生成的中奖号码是7个届于0~9之间的随机数字。

能够用rand来随机生成一注号码。

void main()
{
srand (time (NULL));
int code[7]; // 一注号码为7个数字
for(int i=0; i<7; i++)
{
int r = rand () % 10; // 取模使每一个数字界于0~9之间
code[i] = r;
}
}

注意,一般都要为rand()生的随机数指定一个区间。

生成[100,120]之间的随机数,

int r =  100 + rand () % 20;

生成[0,1]区间的随机小数。

double r = rand()/ (double)RAND_MAX;

当中, RAND_MAX在VC下的定义是32767。在其它操作系统下可能是其它值。

例题:给定10个数,要求从中每次随机选出5个数。

思路:首先,从10个数里面随机挑选出1个数,然后再从剩下的9个数里挑选1个,然后再从剩下的8个数里挑选1个......

设计:用一个flags数组来表示哪个数已经被选中了。比如 flags[3] = 1表示第第4个数已经被选中。flags[9]=0表示第10个数未被选中。

点击查看此节内容。第16章

1.4.3       system 调用系统命令行

用system函数能够调用系统命令行。在windows下能够运行DOS命令行, 在linux下SHELL命令行。比方。删除d:\aaa.pdf这个文件,

system ("del /F /Q  d:\\aaa.pdf");

事实上原则上并不限于DOS命令,所以的命令行都能够执行的。

比如,调用浏览器打开一个站点,

system ("explorer http://www.afanihao.cn");

1.5         string.h

string.h中提供了一系统内存操作函数及字符串操作函数。在学习本节之前,一定要先学习第15章中,掌握字符串的意义。

#include <string.h>

char *strcat(char *s1, const char *s2); // 拼接字符串

char *strchr(char *s, int c);  // 查找字符

int strcmp(const char *s1, const char *s2); // 字符串比較

char *strcpy(char *s1, const char *s2); // 拷贝字符串

char *strstr(char *s1, const char *s2); // 查找子串

size_t strlen(const char *s); // 计算长度

int memcmp(const void *s1, const void *s2, size_t n); //按内存比較

void *memcpy(void *s1, const void *s2, size_t n); // 按内存拷贝

void *memmove(void *s1, const void *s2, size_t n); // 移动数据

void *memset(void *s, int c, size_t n); // 按字节填充内存

1.5.1       strcpy拷贝字符串

strcpy(a,b)用于将字符串b复制到目标缓冲区,

如,

char  buf[128];
strcpy(buf, "LiMing"); // 目标缓冲区内容拷贝为"LiMing"

1.5.2       strcat拼接字符串

strcat(a,b)用于将字符串b拼接于字符串a,也就是说把字符串复制到目标字符串的末尾。

此函数要求目标缓冲区足够大。

#include <string.h>
void main()
{
char a [128] = "hello";
char b [] = "world";
strcat(a, b); // 目标a结果为"helloworld"
}

1.5.3       strcmp比較字符串

关于字符串比較的意义在第15章已经讲述。

strcmp(a,b)用于比較字符串,当返回为0时表示全然相等。小于0时表示a<b,大于0时表示a>b。

int  ret = strcmp("Jack", "Jacky"); // 返回值 ret=-1,表示"Jack"<"Jacky"

1.5.4       strlen求字符串长度

字符串求长度时,结束符'\0'不计算在内。比如,

int  n = strlen("LiMing");   // 返回长度n为6

1.5.5       strchr查找字符

strchr(s, c)用于在字符串s中查找字符c。并返回第一处匹配的位置。

其返回值是char*类型,表示匹配的位置。

char* s = "LiMing";
char* p = strchr(s, 'M'); // 返回值p指向字符'M'的地址
if(p!= NULL)
{
printf("find: %s \n", p);
}

1.5.6       strstr查找子串

点击查看此节内容,第16章

1.5.7       memset内存填充

memset(s, c, n)用于向目标缓冲区s中加入n个同样的字符c。比如,
unsigned char buf[128];
memset(buf, 0, sizeof(buf)); // 所有填充为0
memset(buf, 0xFF, 128); // 所有填充为0xFF
memset(buf, 0x55, 100); // 前100个字节填充为0x55
memset(buf+100, 0x77, 10); // 100..109填充为0x77

1.5.8       memcpy内存拷贝

点击查看此节内容,第16章

1.5.9       memcmp内存比較

点击查看此节内容。第16章

当中。a和b的比較是easy得出结果的 ,但a与c的比較呢?因为要转成unsigned char再比較,所以c>a。

1.5.10    memmove移动数据

memmove(dst, src, n)用于在内存中移动数据,将開始于src的n个字节移动到dst位置,这个函数的强大之处在于它同意src和dst有交迭

比如,利用这个函数我们能够实如今字符串中插入字符,当插入字符串假设将插入点之后的全部字符后移,

点击查看此节内容,第16章

点击查看此节内容,第16章

1.6         stdarg.h

stdarg.h中的接口用于实现省略号參数。在函数中以前指出,函数參数有一个特殊形式。就是不指定个数和类型,直接用省略号表示。

void  test (...)

当參数为省略号时。能够输入随意个数的參数,并且參数的类型不受限制。

我们观察printf函数的原型,发现它就是使用了省略号參数,

int printf(const char *format, ...);

printf的第一个參数为字符串类型。用于传递格式參数, 而后面的省略号处能够传递0..N个參数。这样的灵活的传參方式在某此特殊场合会用到。

以下就指出一种应用需求并给出事实上现方法。

需求:自己定义一个函数用于日志输出,在输出的时候自己主动加入日期时期信息、日志等级,其原型要求是这样的形式。

void log(int level, const char* fmt, ...);

当中, level为日志级别:level=0时。显示ERR, level=1时显示:WRN, level=2时显示INF, level=3时显示DBG。

在调用的时候要求跟printf类似地使用格式化控制符来控制输出,并前缀以日期显示:

log(0,  “My name is %s, I'm %d years old.\n”, “Jennifer”, 30);

此需求实际上就是要实现一个自己定义的打印函数,

#include <stdio.h>
#include <string.h>
#include <stdarg.h> void log(int level, const char* fmt, ...)
{
// 打印日志等级
const char* token = "DBG";
switch(level)
{
case 0: token = "ERR"; break;
case 1: token = "WRN"; break;
case 2: token = "INF"; break;
case 3: token = "DBG"; break;
}
printf("[ %s ] ", token); // 将省略号參数格式化成字符串
char buf[512];
va_list args;
va_start(args, fmt);
vsprintf(buf, fmt, args);
va_end(args); printf(buf);
}
int main()
{
log(2, "Name: %s, Age: %d.\n", "LiMing", 30);
return 0;
}

对省略号參数的核心处理是这几行代码:

va_list args;
va_start(args, fmt);
... 此处已经将參数取得在args里...
va_end(args);

可以以va_list作为參数的函数有vsprintf, vprintf, vfprintf。其原型是:

int vprintf(const char *format, va_list ap); // 输出到控制台

int vsprintf(char *s, const char *format, va_list ap); // 输出到字符串缓冲区

int vfprintf(FILE *stream, const char *format, va_list ap); // 输出到文件流

1.7         习题

1)        求三角函数值:sin(30°),  tan(45°)

2)        取得系统当前的日期和日期。并打印输出。比如“2015-03-03 16:40:01”

3)        某人的生日是1982年3月1日,求出这一天是周几。

4)        当前日期是2015-03-03。请计算出128天以后的日期。并打印出来。

5)        双色球机选一注的规则是:从编号为1,2,...,33的红球内随机选出6个不同的红球,并从编号为1。2。...,16的蓝球内随机选中1个蓝球。

试编写函数。实际机选功能。

void   red_balls (int  selected[] ); // 当中selected为输出參数

void   blue_ball (int* selected); // 当中selected为输出參数

6)        提示用户输入一个字符串:当输入为YES/yes/Yes,打印输出“您已允许”;当输入为NO/no/No时,打印输出“您已拒绝”。

7)        有一段字符文本以\r\n作为行尾结束符,请写一个函数,把每行的内容依次打印出来并在前面加上行号。

比如。输入文本为"Hello\r\nWorld\r\nGood Morning\r\nOK"。输出为:

01 Hello

02 World

03 Goold Morning

04 OK

标准C函数库的使用方法的更多相关文章

  1. UNIX高级环境编程(7)标准IO函数库 - 二进制文件IO,流定位,创建临时文件和内存流

    1 二进制IO(Binary IO) 在前一篇我们了解了逐字符读写和逐行读写函数. 如果我们在读写二进制文件,希望以此读写整个文件内容,这两个函数虽然可以实现,但是明显会很麻烦且多次循环明显效率很低. ...

  2. UNIX高级环境编程(6)标准IO函数库 - 流的概念和操作

    标准IO函数库隐藏了buffer大小和分配的细节,使得我们可以不用关心预分配的内存大小是否正确的问题. 虽然这使得这个函数库很容易用,但是如果我们对函数的原理不熟悉的话,也容易遇到很多问题.   1 ...

  3. 第3章 文件I/O(8)_贯穿案例:构建标准IO函数库

    9. 贯穿案例:构建标准IO函数库 //mstdio.h #ifndef __MSTDIO_H__ #define __MSTDIO_H__ #include <unistd.h> #de ...

  4. ajax的使用:(ajaxReturn[ajax的返回方法]),(eval返回字符串);分页;第三方类(page.class.php)如何载入;自动加载函数库(functions);session如何防止跳过登录访问(构造函数说明)

    一.ajax例子:ajaxReturn("ok","eval")->thinkphp中ajax的返回值的方法,返回参数为ok,返回类型为eval(字符串) ...

  5. Phpcms v9系统类库与函数库调用方法

    在分享了n多phpcms的教程后,cmsyou继续分享关于phpcms v9系统类库与函数库的调用方法. 系统类库位于系统的 /libs/functions目录下面,函数库文件名为*.func.php ...

  6. [Effective JavaScript 笔记]第28条:不要信赖函数对象的toString方法

    js函数有一个非凡的特性,即将其源代码重现为字符串的能力. (function(x){ return x+1 }).toString();//"function (x){ return x+ ...

  7. Underscore——JS函数库

    转载请注明原文地址:https://www.cnblogs.com/ygj0930/p/10826065.html underscore是什么——它是一个js函数库 jQuery统一了不同浏览器之间的 ...

  8. javaweb学习总结(三十)——EL函数库

    一.EL函数库介绍 由于在JSP页面中显示数据时,经常需要对显示的字符串进行处理,SUN公司针对于一些常见处理定义了一套EL函数库供开发者使用. 这些EL函数在JSTL开发包中进行描述,因此在JSP页 ...

  9. javaWeb学习总结(10)- EL函数库(2)

    一.EL函数库介绍 由于在JSP页面中显示数据时,经常需要对显示的字符串进行处理,SUN公司针对于一些常见处理定义了一套EL函数库供开发者使用. 这些EL函数在JSTL开发包中进行描述,因此在JSP页 ...

随机推荐

  1. 《转》读discuzx3.1 数据库层笔记

    最近开始在看discuzx3.1的代码,看到数据库层的实现,discuzx的数据库层能够支撑数据库分库,分布式部署,主要水平分表,也可以很方便的支持其他数据库.性能上,可以做读写分离,支持数据缓存.可 ...

  2. 用不动点组合子解递归(python实现)

    不动点组合子 Y = λf. (λx. f (x x)) (λx. f (x x)) θ = (λx. λy. (y(x x y))) (λx.λy.(y(x x y))) Y f = f (Y f) ...

  3. cad移动图案

    1.键盘按快捷键M,鼠标变成小方块,选中图案,右击,左击拖动图像 2.选中图像,键盘按m,拖动图像 3.选中图像,右击,图像移动

  4. Java学习之InputStream中read()与read(byte[] b)

    Java学习之InputStream中read()与read(byte[] b) 这两个方法在抽象类InputStream中都是作为抽象方法存在的, JDK API中是这样描述两者的: read() ...

  5. HDU 5716 带可选字符的多字符串匹配(ShiftAnd)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5716 [题目大意] 给出一个字符串,找出其中所有的符合特定模式的子串位置,符合特定模式是指,该子串 ...

  6. 在Mac上配置Apache+PHP环境

    1.启用Apache/Web共享 打开终端,运行启动Apache命令: sudo apachectl start 然后输入系统密码,运行成功. 关闭命令: sudo apachectl stop 重启 ...

  7. POJ 1077 HDU 1043 Eight (IDA*)

    题意就不用再说明了吧......如此经典 之前想用双向广搜.a*来写,但总觉得无力,现在用IDA*感觉其他的解法都弱爆了..............想法活跃,时间,空间消耗很小,给它跪了 启发式搜索关 ...

  8. CouchDB简单应用

    CouchDB是众多称作NoSQL解决方案中的一员.与众不同的是,CouchDB是一个面向文档的数据库,在它里面所有文档域(Field)都是以键值对的形式存储的.域(Field)可以是一个简单的键值对 ...

  9. QT国际化

    写的比较简洁 语言文件: ts:编辑翻译用的,是xml,可以用linguist(qt语言专家)或者Editplus进行翻译 qm:这种文件是ts的release版,无法编辑,发布的时候用这个 操作: ...

  10. 我用过的Linux命令之chmod

    chmod命令用于改变linux系统文件或目录的访问权限.用它控制文件或目录的访问权限.该命令有两种用法.一种是包含字母和操作符表达式的文字设定法:另一种是包含数字的数字设定法. Linux系统中的每 ...