在说到字符串的时候,提到了很多字符串处理函数,尤其是strcpy函数的运用最为广泛,本节将详细的分析下几个常用的标准库函数,在将给编程带来极大的方便。而C的面试题中经常性会出现对标准库函数的熟练运用。
e.g.1编写一个函数,作用是把一个char组成的字符串循环右移n个。比如原来是“abcdefghi”,如果n=2,移动后应该是“hiabcdefg”。
函数头是这样的:
//pStr是指向以'\0'结尾的字符串的指针
//steps是要求移动的n
void LoopMove(char *pStr,int steps)
{
//请补充
}
解决这个问题之前我们还是来总结一下常见的标准库函数以及它的原型:
标准头文件包括:
<asset.h><ctype.h><errno.h><float.h><limit.h>
<locale.h><math.h><setjmp.h> <signal.h> <stdarg.h>
<stddef.h><stdlib.h> <stdio.h> <string.h> <time.h>
在根据这些头文件我们再来总结下常见的一些函数:
(1)输入输出函数(stdio.h)
关于输入输出函数,我们在C文件系统这一节基本都提到了:http://blog.youkuaiyun.com/gzbaishabi/article/details/38751291
(2)数学函数(math.h)
这里面主要提供了一些数学的函数运算,大体上可以分为三类:三角函数(反三角函数)、指数(幂)函数、基本运算函数
三角函数:
三角函数 | sin | cos | tan |
反三角函数 | asin | acos | atan |
双曲函数 | sinh | cosh | tanh |
指数和对数函数:
以e为底的指数函数 | exp |
自然对数函数 | log |
以10为底的对数函数 | log10 |
其他函数:
平方根 | sqrt |
绝对值 | fabs |
乘幂,第一个参数作为底,第二个是指数 | double pow(double, double) |
实数的余数,两个参数分别是被除数和除数 | double fmod(double, double) |
另外关于fabs与abs的区别:
fabs的函数原型:
extern float fabs(float x);
abs的函数原型:(3)字符串处理函数(<string.h>)abs(x);//是针对整数的
关于字符处理函数,在之前的字符串处理函数中基本已提及,其中的strcpy函数是经常性使用的。见:http://blog.youkuaiyun.com/gzbaishabi/article/details/38822369
但是除了已经提及的,在字符串处理函数中经常性用到的一些关于存储区操作的也是必须要掌握的。
在<string.h>有一些字符数组的操作函数(存储区操作),名字是以mem开头的,它的方式更加高效。在下面原型中,参数s和t的类型是(void*),cs和ct的类型是(const void *),n的类型是size_t,c的类型是int(转换为unsigned char)。
void *memcpy(s,ct.,n);//从ct处复制n个字符到s中,返回s
vodi *memmove(s,ct,n);//从ct处复制n个字符到s中,返回s,且二者允许重叠
int *memcmp(cs,ct,n);//比较由cs、ct开始的n个字符,返回值分别可以正值、0、负值
void *memchr(cs,c,n);//在n个字符范围内,查找c在cs中第一次出现。如果找到返回位置的指针值
void *memset(s,c,n);//将s的前n个字符全部置为c
注意:在strlen和strcpy两个函数考察中,经常会出现数组越界的问题。因此这里需要注意几个问题:
(1)使用strcpy函数的时候一定要注意前面数码的数组大小必须大于后面字符串的大小,否则会访问越界。
(2)字符数组和字符串的最明显区别是字符串会默认地加上结束符
(3)字符数组并不要求最后一个字符为'\0'。是否加上完全由系统决定。但是字符数组的初始化要求最后一个字符必须为’\0‘。
(4)strlen函数得到字符串除了结束符外的长度。
(4)字符处理函数(<ctype.h>)
见下表:
int isalpha(c) | c是字母字符 |
int isdigit(c) | c是数字字符 |
int isalnum(c) | c是字母或数字字符 |
int isspace(c) | c是空格、制表符、换行符 |
int isupper(c) | c是大写字母 |
int islower(c) | c是小写字母 |
int iscntrl(c) | c是控制字符 |
int isprint(c) | c是可打印字符,包括空格 |
int isgraph(c) | c是可打印字符,不包括空格 |
int isxdigit(c) | c是十六进制数字字符 |
int ispunct(c) | c是标点符号 |
int tolower(int c) | 当c是大写字母时返回对应小写字母,否则返回c本身 |
int toupper(int c) | 当c是小写字母时返回对应大写字母,否则返回c本身 |
(5)功能函数(<stdlib.h>)
动态存储分配函数:
void *malloc(size_t size);//动态分配size个单位的空间
void *calloc(size_t n,size_t size);//分配足以存放n个大小为size的对象,并将所有字节用0填充,返回该存储块的地址
void *realloc(void *p,size_t size);//将p所指的存储块调整为大小为size,返回新块的地址
void free(*p);//释放当前所指
<errno.h>定义了一个int类型的表达式errno,可以看作一个变量,其初始值为0,一些标准库函数执行中出错时将它设为非0值,但任何标准库函数都设置它为0。
<errno.h>里还定义了两个宏EDOM和ERANGE,都是非0的整数值。数学函数执行中遇到参数错误,就会将errno置为EDOM,如出现值域错误就会将errno置为ERANGE。
另外一些标准库函数,随着学习的过程会不断陆续增加。
现在再来分析这个问题:
e.g.1编写一个函数,作用是把一个char组成的字符串循环右移n个。比如原来是“abcdefghi”,如果n=2,移动后应该是“hiabcdefg”。
函数头是这样的:
//pStr是指向以'\0'结尾的字符串的指针
//steps是要求移动的n
void LoopMove(char *pStr,int steps)
{
//请补充
}
分析:这其实就是堆标准库函数的熟练使用,尤其是strcpy、memcpy、memset
解答1:
void LoopMove(char *pStr,int steps)
{
int n = strlen(pStr) - steps;
char tmp[MAX_LEN];
memcpy(tmp,pStr+n,steps);//将pStr+n所指的字符串复制steps个字符到tmp中去,
//完成了hi到最前面的操作
memcpy(pStr+steps,pStr,n<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;">);//将pStr中的前n个字符复制到pStr+steps处,这就完成了pStr中前7个字符到数组pStr第三个位置开始处</span>
<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;"> memcpy(pStr,tmp,steps);完成操作</span>
解答2:是否可以用strcpy完成操作?
void LoopMove(char *pStr,int steps)
{
int n = strlen(pStr)-steps;
char tmp(MAX_LEN);
strcpy(tmp,pStr+n);
strcpy(tmp+steps,pStr);
*(tmp+strlen(pStr))='\0';
strcpy(pStr,tmp);
}