库函数能提供给我们最显著的作用就是提高工作效率,在我们初学阶段使用库函数来实现一些简单的算法其实是很常见的,那么了解一些库函数的功能及其实现过程就很有必要了。
首先我们来看看strcmp和strncmp的用法和区别:
函数名:strcmp
原 型:extern int strcmp (const char *s1, const char *s2)
功 能:这个函数用来比较s1和s2字符串,这个函数将返回一个值.如全部字符相同,则认为两个字符串相等; 若出现不相同的字符,则以第一对不相同的字符比较结果为准。
说 明: 当s1
当s1==s2时,返回值为0;
当s1>s2时,返回值为正整数(注意也不一定是1)
字符串的比较规则:将两个字符串自左至右逐个字符比较(按ASCII码值大小比较),直到出现不同的字符或遇 到'\0'为止。
特别注意:strcmp(const char*s1,const char*s2)这里只能比较字符串,不能比较数字等其他形式的参数。
模拟实现:
#include
#include
#include
int my_strcmp(const char*arr,const char *str)
{
assert(arr);
assert(str);
while(*arr==*str)
{
if(*arr=='\0')
return 0;
arr++;
str++;
}
return (*arr-*str);
}
int main()
{
char *str1="abcda";
char *str2="abcde";
int ret=0;
ret=my_strcmp(str1,str2);
if(ret==0)
printf("str1==str2\n");
else if(ret>0)
printf("str1>str2\n");
else
printf("str1
函数名:strncmp
原 型:int strncmp (const char *s1, const char *s2, size_t size)
功 能: 此函数与strcmp极为类似。不同之处是,strncmp函数是指定比较size个字符。也就是说,如果字符 串s1与s2的前size个字符相同,函数返回值为0; 如果字符串s1与s2的前size个字符不等,函数返回值为 *s1-*s2;
模拟实现:
#include
#include
#include
int my_strncmp(const char*arr,const char *str,int k)
{
assert(arr);
assert(str);
while(k--)
{
if(*arr==*str)
{
while(*arr=='\0')
return 0;
arr++;
str++;
}
else
return (*arr-*str);
}
if(k==0)
return 0;
}
int main()
{
char *str1="abcde";
char *str2="bcda";
int k=0;
int ret=0;
printf("请输入要比较的字符串个数:\n");
scanf("%d",&k);
ret=my_strncmp(str1,str2,k);
if(ret==0)
printf("str1=str2\n");
else if(ret>0)
printf("str1>str2\n");
else
printf("str1
接下来让我们再看看strcpy和strncpy这两个函数:
函数名:strcpy
原 型:extern char *strcpy(char *dest,char *src);
功 能:把从src地址开始且含有NULL结束符的字符串赋值到以dest开始的地址空间,返回dest(地址中存储 的为复制后的新值)。
注 意:(1)src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。
(2)字符数组dest必须写成数组名的形式,字符数组src可以是字符数组名,也可以是字符串常量。例 如:strcpy(dest,"China");
(3)如果在拷贝前未对dest数组初始化或赋值,则dest各字节中的内容是无法预知的,所以记得要对其 初始化哦!
模拟实现:
#include
#include
#include
char *my_strcpy(char *dest, const char *src)
{
char *ret=dest;
assert(dest);
assert(src);
while(*src)
{
*dest++=*src++;
}
return ret;
}
int main()
{
char arr[10]="\0";
char str[]="China";
my_strcpy(arr, str);
printf("%s",arr);
system("pause");
return 0;
}
函数名:strncpy
原 型:extern char *strcpy(char *dest,char *src,size_t num);
功 能:(c/c++)复制src中的内容到dest,复制多少由num的值决定,返回指向dest的指针
说 明:如果num > dest串长度,dest栈空间溢出产生崩溃异常。
1)src串长度<=dest串长度,(这里的串长度包含串尾NULL字符)
如果n = src串长度,与strcpy一致;
如果n >src串长度,dest就包含两部分,从源src复制过来的和dest原来初始化的内容(根据初始化的内 容来看,不一定为'\0')的最后num-n个字符。
2)src串长度>dest串长度
如果n =dest串长度,则dest串没有NULL字符,会导致输出会有乱码。如果不考虑src串复制完整 性,可以将dest 最后一字赋值为NULL。
一般情况下,使用strncpy时,建议将n置为dest串长度(除非你将多个src串都复制到dest数组, 并且从dest尾部反向操作),复制完毕后,为保险起见,将dest串最后一字符置NULL,避免发生输出乱码问题。当然喽,无论是strcpy还是strncpy,保证dest串容量(能容纳下src串)才是最重要的。
模拟实现:
#include
#include
#include
char *my_strncpy(char *dest, const char *src,int n)
{
char *ret=dest;
assert(dest);
assert(src);
while(n--)
{
*dest++=*src++;
}
*dest='\0';
return ret;
}
int main()
{
int n=0;
char arr[10]="\0";
char str[]="China";
printf("请输入要拷贝的字符个数:\n");
scanf("%d",&n);
my_strncpy(arr, str,n);
printf("%s",arr);
system("pause");
return 0;
}
如果需要拷贝一个比较大的字符串呢,用strncpy该如何优化才能提高效率呢,我们是不是可以考虑进行多个字节一拷贝呢,当然在32位进制的计算机上通常指的是4个字节一拷贝咯。说到这,那memcpy和memmove这两个函数好像更能达到优化的效果哦!下来让我们去比较一下它们的优缺:
首先描述一下这三个相关函数strcpy/strncpy、memcpy和memmove的意义。
众所周知的,strcpy/strncpy和memcpy都是用于从一块内存复制一段连续的数据到另一块内存,区别在于终结标识不同。strcpy会比较每个字符是否为'\0'以判定是否继续复制,而memcpy就不管内存数据内容,确定复制指定的长度(不讨论源串有错误或者目的空间不够等出错的情况)。所以这两者在作用上是可以共通的,我想这两个函数最大的区别只能说是语义上的区别。而用法上,strcpy只能针对字符串,memcpy却没有这个限制,用memcpy(char *pDest,char *pSource,strlen(pSource))完全能替代strcpy的功能。
而后面两个mem系列函数,主要区别在memcpy对于重叠内存的复制支持不太好。例如对char a[10]操作的话,memcpy(a, a + 3, 5)这样的,源数据是a+3到a+7,目标位置是a到a+5,操作区域有重复,则应该用memmove。
下来简述一下memcpymemmove的区别:
原型:void *memcpy(void *dst, const void *src, size_t count);
void *memmove(void *dst, const void *src, size_t count);
功能:memcpy与memmove的目的都是将count个字节的源内存地址的内容拷贝到目标内存地址中。
但当源内存和目标内存存在重叠时,memcpy会出现错误,而memmove能正确地实施拷贝,但这也 增加了一点点开销。
memmove的处理措施:
(1)当源内存的首地址等于目标内存的首地址时,不进行任何拷贝
(2)当源内存的首地址大于目标内存的首地址时,实行正向拷贝
(3)当源内存的首地址小于目标内存的首地址时,实行反向拷贝
从功能上来说,用memcpy(char *pDest,char *pSource,strlen(pSource))完全能替代strcpy的功能,当然memmove安全性更高一些。之所以倡导这种用法,在于用memcpy/memmove函数不仅功能上比strcpy/strncpy更强大,关键在于前者效率要高很多!尽管没有这两个函数的源代码,但是单从分析上,strcpy/strncpy需要在每一步操作时都要比较字符是否为'\0',而memcpy/memmove完全不需要,甚至有更快的指令来优化块复制,所以效率肯定高很多。
关于拷贝这一块儿呢就暂且介绍到这里,然后我们进入到下一个模块:
连接函数:strcat和strncat
函数名:strcat
原 型:extern char*strcat(char *dest,coonst char *src)
功 能:把src所指字符串添加到dest结尾处(覆盖dest结尾处的'\0')并添加'\0'。
说 明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串;
返回指向dest的指针。
模拟实现:
#include
#include
#include
char *my_strcat(char *str,const char *dest)
{
char *pret=str;
assert(str);
assert(dest);
while(*str)
{
str++;
}
while(*str++=*dest++)
{
;
}
*str='\0';
return pret;
}
int main()
{
char arr[20]="abcdef";
char str[]="aac";
my_strcat(arr,str);
printf("%s",arr);
system("pause");
return 0;
}
strncat函数
原 型:extern char *strncat(char *dest,char *src,int n);
功 能:把src所指字符串的前n个字符添加到dest结尾处(覆盖dest结尾处的'\0')并添加'\0'。
说 明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串;
返回指向dest的指针。
模拟实现:
#include
#include
#include
#include
char *my_strncat(char *str,const char *dest,int len)
{
char *pret=str;
assert(str);
assert(dest);
if(*dest=='\0')
return 0;
while(*str)
{
str++;
}
while(len--)
{
*str++=*dest++;
}
*str='\0';
return pret;
}
int main()
{
char arr[20]="abcdef";
int len=strlen(arr);
my_strncat(arr,arr,len); //这里实现的是字符串与字符串自身进行连接
printf("%s",arr);
system("pause");
return 0;
}
最后呢,我们再来看一下strstr这个函数:
函数名:strstr
原 型:extern char *strstr(const char *str,const char *substr)
功 能:strstr()函数搜索一个字符串在另一个字符串中的第一次出现。该函数返回字符串的其余部分 (从匹配点)。如果未找到所搜索的字符串,则返回 false。
注 释:如果该参数是数字,则搜索匹配数字ASCII值的字符。该函数对大小写敏感。如需进行大小写不 敏感的搜索,请使用 stristr()。
模拟实现:
#include
#include
#include
char* my_strstr(const char *str, const char *substr)
{
const char* str1 = str;
const char* str2 = substr;
const char *start = NULL;
assert(str);
assert(substr);
if(*str2 == '\0')
return (char *)str1;
while(*str1)
{
start = str1;
while( *str1 && *str2 && *str1 == *str2)
{
str1++;
str2++;
}
if(*str2 == '\0')
return (char*)start;
str1 = start+1;
str2 = substr;
}
return NULL; //函数的返回类型
}
int main()
{
char *str=NULL;
str=my_strstr("abcde","bcd");
if(str!=NULL)
{
printf("%s\n",str);
}
else
{
printf("matched fail\n");
}
system("pause");
return 0;
}
最后再提醒一句,这些都是库函数,在直接使用它们的时候记得引头文件#include
先暂时介绍这些库函数吧,作为初学者呢,希望大家多多提点啊!
函数名