C语言K&R圣经笔记 7.7行输入和输出 7.8其他函数

7.7 行输入和输出

标准库提供了一个输入例程 fgets,类似于我们在之前章节使用过的 getline 函数:

char *fgets(char *line, int maxline, FILE *fp)

fgets 从文件 fp 中读取下一个输入行(包括换行符)到字符数组 line 中;最多读入 maxline-1 个字符。结果行以 '\0' 结尾。 fgets 通常返回 line;若遇到文件结束或错误则返回 NULL。(我们的getline 返回行的长度,这个返回值更有用;若文件结束则返回 0。)

至于输出, 有 fputs 函数写一个字符串(不必包含换行符)到文件中:

int fputs(char *line, FILE *fp)

如果遇到错误会返回EOF,否则返回 0。

库函数 gets 和 puts 类似 fgets 和 fputs,不过操作的是 stdin 和 stdout。令人困惑的是,gets 删除结尾的 '\n',而 puts 在结尾添加 '\n'。

为了说明 fgets 和 fputs 这样的函数也没什么特别的,这里把它们源代码从我们系统的标准库中拷贝出来,给大家看看:

/* fgets: 从 iop 中获取最多 n 个字符 */
char *fgets(char *s, int n, FILE *iop)
{
    register int c;
    register char *cs;

    cs = s;
    while (--n > 0 && (c = getc(iop)) != EOF)
        if ((*cs++ = c) == '\n')
            break;
    *cs = '\0';
    return (c == EOF && cs == s) ? NULL : s;
}

/* fputs: 写字符串到文件iop */
int fputs(char *s, FILE *iop)
{
    int c;

    while (c = *s++)
        putc(c, iop);
    return ferror(iop) ? EOF : 0;
}

标准库规定 ferror 在错误时返回非零;fputs 在错误时返回 EOF,其他情况下返回非负数。

可以很容易用 fgets 来实现我们的 getline:

/* getline:读一行,返回长度 */
int getline(char *line, int max)
{
    if (fgets(line, max, stdin) == NULL)
        return 0;
    else
        return strlen(line);
}

练习7-6、写个程序来比较两个文件,打印出它们的第一个差异行。
练习7-7、修改第五章的样式搜索程序,使其从一系列文件中获取输入,如果没有给出文件名做参数,则用标准输入。当找到匹配行时,是否应当输出文件名?
练习7-8、写个程序打印一系列文件,每个文件从新的一页开始,带标题和页码。

7.8 其他函数

标准库提供了种类繁多的函数。本节是对其中最常用部分的概述。更多的细节和更多其他函数,参见附录B。


7.8.1 字符串操作


我们已经提到过 <string.h> 中的字符串函数 strlen, strcpy, strcat 和 strcmp 。在下面的描述中, s 和 t 是 char * 类型,而 c 和 n 是 int 类型。

strcat(s,t)             连接 t 到 s 的末尾
strncat(s,t,n)        连接 t 的 n 个字符到 s 的末尾
strcmp(s,t)           在 s < t ,s == t 或 s > t 时分别返回负数,0 和 正数 
strncmp(s,t,n)      与 strcmp 一样,但只比较前 n 个 字符
strcpy(s,t)             把 t  拷贝到 s
strncpy(s,t,n)        最多拷贝 t 的 n 个字符到 s
strlen(s)                返回 s 的长度
strchr(s,c)             返回 s 中第一个 c 的指针,若没有则返回 NULL
strtchr(s,c)            返回 s 中最后一个 c 的指针,若没有则返回 NULL


7.8.2 字符类型判断和转换


一些来自 <ctype.h>的函数执行字符判断和转换。在下面的描述中,c 是可以表示为 unsigned char 或 EOF 的一个 int。这些函数返回 int。

isalpha(c)        若 c 为字母则返回非0,否则返回0
isupper(c)        若 c 为大写则返回非0,否则返回0
islower(c)         若 c 为小写则返回非0,否则返回0
isdigit(c)           若 c 为数字则返回非0,否则返回0
isalnum(c)        若 isalpha(c) 或 isdigit(c) 则返回非0,否则返回0
isspace(c)        若 c 为空格、制表符、换行符、回车符、换页符、垂直制表符则返回非0
toupper(c)        返回转换成大写后的 c
tolower(c)         返回转换成小写后的 c


7.8.3 ungetc

我们在第四章写过 ungetch 函数,标准库提供了一个更加受限的版本;称为 ungetc

int ungetc(int c, FILE *fp)

将字符 c 推回给文件 fp 并返回 c,或遇到错误则返回 EOF。每个文件只保证推回一个字符。ungetc 能够与任意输入函数如 scanf,getc 或 getchar 一起使用。

7.8.4 命令执行


system(char *s) 函数执行字符串 s 中的命令,然后继续当前程序的执行。s 的内容强依赖于本地系统。举个UNIX系统上的小例子,如下语句

system("date");


使程序 date 被执行;它在标准输出上打印日期和时间。 system 从被执行的命令中返回一个依赖于系统的整数。在 UNIX 系统中,返回的状态是 exit 返回的值。

7.8.5 内存管理

函数 malloc 和 calloc 动态地获取内存块。

void *malloc(size_t n)

返回一个指针,指向 n 个字节的未初始化的内存空间,若无法满足要求则返回 NULL。

void *calloc(size_t n, size_t size)

返回一个指针,指向能容纳 n 个指定大小为 size 的对象的数组空间,若无法满足要求则返回 NULL。内存空间初始化为零。

malloc 和 calloc 返回的指针为所需的对象提供了正确的对齐,但必须要转换成恰当的类型,例如

int *ip;

ip = (int *) calloc(n, sizeof(int));

free(p) 释放 p 指向的内存空间,其中 p 最初是通过调用 malloc 或 calloc 得到的。空间的释放顺序是随意的,但释放并非由调用 calloc 或 malloc 得到的内存是非常可怕的错误。

在内存释放后继续使用也是错误的。下面这段在链表中循环释放元素的代码非常典型,但却是错误的:

for (p = head; p != NULL; p = p->next)     /* 错误 */
    free(p);

 
正确的方法是在释放之前保存需要的内容

for (p = head; p != NULL; p = q) {
    q = p->next;
    free(p);
}

8.7 给出了一个类似 malloc 的内存管理器的实现,其中分配的内存块可以自由地以任意顺序释放。

7.8.6 数学函数

<math.h> 中定义了超过 20 个数学函数;这里给出一些使用最频繁的。每个函数都要一个或两个double 参数,并返回 double。

sin(x)                x 的正弦,x 为弧度
cos(x)               x 的余弦,x 为弧度
atan2(y,x)         y/2 的反正切,xy为弧度
exp(x)               e 的 x 次方
log(x)                x 的自然对数(x > 0)
log10(x)            x 的常用对数(x > 0)
pow(x,y)            x 的 y 次方
sqrt(x)                x 的平方根( x >= 0)
fabs(x)               x 的绝对值


7.8.7 随机数生成

函数 rand 计算出范围从 0 到 RAND_MAX(在<stdlib.h>中定义)的伪随机整数序列。生成大等于0但小于1的伪随机浮点数的一种方法是

#define frand() ((double) rand() / (RAND_MAX + 1.0))

(如果你的库已经提供了获取浮点随机数的函数,则它可能比上面这个有更好的统计特性。)

函数 srand(unsigned) 设置 rand 的种子。标准建议的可移植的 rand 和 srand 的实现,参见 2.7节。


练习7-9、像 isupper 这样的函数可以实现为节省空间或节省时间。探索两种可能性。


(第七章完)
 

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值