C语言库函数探究
1、strlen()求字符串长度
//模拟实现strlen函数
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
int my_strlen1(const char* str) //借助临时变量实现
{
int count = ;
while (*str++)
{
count++;
}
return count;
}
int my_strlen2(char* s)
{
char* p = s;
/*while (*p != '\0')
p++;*/
while (*p++);
return p - s - ;
}
int my_strlen3(char* str) //递归法
{
if (!*str)
return ;
else
return + my_strlen3(str + );
}
int main()
{
char src[] = "qwertyuiop";
int num1 = my_strlen1(src);
int num2 = my_strlen2(src);
int num3 = my_strlen3(src);
printf("%d\n", num1);
printf("%d\n", num2);
printf("%d\n", num3);
getchar();
return ;
}
2、strcpy()字符串拷贝函数
char* my_strcopy1(char* dest, const char* str)
{
assert(dest != NULL);
assert(str != NULL);
char* ret = dest;
while (*dest++ = *str++)
{
;
}
return ret;
}
char* my_strcopy2(char* dest, const char* str)
{
assert(dest != NULL);
assert(str != NULL);
char* ret = dest;
while (*str != '\0')
{
*dest = *str;
dest++;
str++;
}
*dest = *str;
return ret;
}
int main()
{
char str[] = "abcdefg";
char dest1[];
char dest2[];
my_strcopy1(dest1, str);
my_strcopy2(dest2, str);
printf("%s\n", dest1);
printf("%s", dest2);
getchar();
return ;
}
(1)字符数组dest1和dest2必须定义得足够长,以容纳复制进去的字符串;
(2)与其相关的还有strncpy()函数定义拷贝固定长度的字符
strncpy(str1, str2);
作用是将str2中前2个字符复制到str1中,取代str1中原有的前两个字符,N应不大于str1原字符长度(不包括‘\0’)。
3、strcmp()字符串比较函数
int my_strcmp(const char *str1, const char *str2)
{
while (*str1 == *str2)
{
if (*str1 == '\0')
return ;
else
{
str1++;
str2++;
}
}
return (*str1 - *str2);
}
int main()
{ printf("%d\n", my_strcmp("awc", "aaaa")); //输出大于0的数
printf("%d\n", my_strcmp("ac", "aw")); //输出小于于0的数
printf("%d\n", my_strcmp("awc", "awc")); //输出0
printf("%d\n", strcmp("awc", "aaaa")); //输出1
printf("%d\n", strcmp("ac", "aw")); //输出-1
printf("%d\n", strcmp("awc", "awc")); //输出0
getchar();
return ;
}
4、strcat()字符串连接函数
char *my_strcat(char *dest, const char *str)
{
char *ret = dest;
assert(dest != NULL);
assert(str != NULL);
while (*dest != '\0')
{
dest++;
}
while (*dest++ = *str++)
{
;
}
return ret;
}
int main()
{
char arr[] = "abcdefg";
my_strcat(arr, "hit");
printf("%s\n", arr);
getchar();
return ;
}
5、strstr()找子串(模式匹配)
原型可以写成:char *my_strstr(const char *str, const char *substr)
char substr = "ababa";


代码如下:
char *my_strstr(const char *str, const char *dest)
{
const char *str1 = NULL;
const char *str2 = NULL;
const char *start = str;
assert(str);
assert(dest);
if (*dest == NULL)
{
return (char *)str;
}
while (*start)
{
str1 = start;
str2 = dest;
while ((*str1) && (*str2) && (*str1 == *str2))
{
str1++;
str2++;
}
if (*str2 == '\0')
{
return (char *)start;
}
start++;
}
return NULL;
}
int main()
{
char str1[] = "ababcababa";
char str2[] = "ababa";
char *ret = my_strstr(str1, str2);
if (ret != NULL)
printf("%s\n", ret);
else
printf("not exit!\n");
getchar();
return ;
}
(2)介绍另外一种方法,KMP算法

这时,按第一种方法是,将目标串整个后移一位,再从头逐个比较。这样做虽然可行,但是效率很差,因为你要把"查找位置"移到已经比较过的位置,重比一遍。一个基本事实是,当 i=4,j=4 c与a不匹配时,你其实知道前面四个字符是"abab"。KMP算法的想法是,设法利用这个已知信息,不要把"查找位置"移回已经比较过的位置,继续把它向后移,这样就提高了效率。

我们可以针对搜索词,算出一张《部分匹配表》如上表。这张表是如何产生的,后面会介绍,这里先看它的用法。

已知c与a不匹配时,前面四个字符"abab"是匹配的。查表可知,最后一个匹配字符b对应的"部分匹配值"为0,因此按照下面的公式算出向后移动的位数:
移动位数 = 已匹配的字符数 - 对应的部分匹配值
4 - 0 等于4,所以将搜索词向后移动4位。

因为a与c不匹配,搜索词还要继续往后移。这时,已匹配的字符数为0,对应的"部分匹配值"为0。所以后移一位

逐位比较,直到搜索词的最后一位,发现完全匹配,于是搜索完成。如果目标字符串后面还有,还要继续搜索的话(即找出全部匹配),移动位数 = 5 - 3,再将搜索词向后移动2位,这里就不再重复了。
下面介绍部分匹配值的算法:

上图中后缀是从后往前看的,写成正序应为: a, ba, aba, baba 最后一个a不算在内。
"部分匹配值"就是"前缀"和"后缀"的最长的共有元素的长度。以"ababa"为例:
- "a"的前缀和后缀都为空集,共有元素的长度为0;
- "ab"的前缀为[a],后缀为[b],共有元素的长度为0;
- "aba"的前缀为[a, ab],后缀为[ba, a],共有元素的长度1;
- "abab"的前缀为[a, ab, aba],后缀为[bab, ab, b],共有元素的长度为2;
- "ababa"的前缀为[a, ab, aba, abab],后缀为[baba, aba, ba, a],共有元素为"aba",长度为3;
next数组的求解思路(即部分匹配值)
通过上文完全可以对kmp算法的原理有个清晰的了解,那么下一步就是编程实现了,其中最重要的就是如何根据待匹配的模版字符串求出对应每一位的最大相同前后缀的长度。
void makeNext(const char* str,int next[])
{
int num,max;//num:模版字符串下标;max:最大前后缀长度
int len = strlen(str);//模版字符串长度
next[] = ;//模版字符串的第一个字符的最大前后缀长度为0
for (num = ,max = ; num < len; ++num)//for循环,从第二个字符开始,依次计算每一个字符对应的next值
{
while(max > && str[num] != str[max])//递归的求出dest[0]···dest[n]的最大的相同的前后缀长度max
max = next[max - ];
if (str[num] == str[max])//如果相等,那么最大相同前后缀长度加1
{
max++;
}
next[num] = max;
}
}
int kmp(const char str[],const char dest[],int next[])
{
int slen, dlen;
int i,n;
slen = strlen(str); //长字符串的长度
dlen = strlen(dest); //目标字符串长度
makeNext(dest,next);
for (i = ,n = ; i < slen; ++i)
{
while(n > && dest[n] != str[i])
n = next[n-]; //目标字符串下标n回退
if (dest[n] == str[i])
{
n++;
}
if (n == dlen) //找到目标串,返回目标串起始下标
{
printf("Pattern occurs with shift:%d\n",(i - dlen + ));
}
}
} int main()
{
int i;
int next[]={};
char str[] = "ababxbababcadfdsss";
char dest[] = "abcdabd";
printf("%s\n",str);
printf("%s\n",dest);
// makeNext(dest, next);
kmp(str, dest, next);
for (i = ; i < strlen(dest); ++i)
{
printf("%d ",next[i]);
}
printf("\n"); return ;
}
KMP算法的时间复杂度为O(m+n);空间复杂度为O(n)。
6、strlwr将字符串中的字符转换为小写
原型为:char *strlwr(char *str);
参数说明:str为要转换的字符串。
返回值:返回转换后的小写字符串,其实就是将str返回。
strlwr() 不会创建一个新字符串返回,而是改变原有字符串。所以strlwr()只能操作字符数组,而不能操作指针字符串,因为指针指向的字符串是作为常量保存在静态存储区的,常量不能被修改
注意:strlwr()和不是标准库函数,只能在windows下(VC、MinGW等)使用,Linux
GCC中需要自己定义。
char* my_strlwr(char *str)
{
assert(str);
char* start = str;
while (*start)
{
if (*start >= 'A' && *start <= 'Z')
*start += ;
start++;
}
return str;
}
char* my_strupr(char *str)
{
assert(str);
char* start = str;
while (*start)
{
if (*start >= 'a' && *start <= 'z')
*start -= ;
start++;
}
return str;
}
int main()
{
char str1[] = { "ABCDCFbbbdgeJhssW" }; printf("%s\n", my_strlwr(str1)); //调用该函数,并且输出新的字符串
printf("%s\n", my_strupr(str1)); //调用该函数,并且输出新的字符串
getchar();
return ;
}
7、memcpy内存拷贝函数
函数原型:void *memcpy(void *dest, const void *src, size_t n);
功能:从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中。
返回值:函数返回指向dest的指针。
说明:1.source和destin所指的内存区域可能重叠,但是如果source和destin所指的内存区域重叠,那么这个函数并不能够确保source所在重叠区域在拷贝之前不被覆盖。而使用memmove可以用来处理重叠区域。函数返回指向destin的指针。
void *my_memcpy(void *dest, const void *str, int sz)
{
int i = ;
char *pdest = (char *)dest;
char *pstr = (char *)str;
assert(dest);
assert(str);
for (i = ; i < sz; i++)
{
*pdest = *pstr;
pdest++;
pstr++;
}
return dest;
}
int main()
{
int i = ;
int arr1[] = { , , , , , , , };
int arr2[];
my_memcpy(arr2,arr1,*sizeof(int));
for (i = ; i < sizeof(arr2) / sizeof(arr2[]); i++)
{
printf("%d\n", arr2[i]);
}
getchar();
return ;
}
8、memmove内存拷贝函数
函数原型:void *memmove(void *dest, const void *src, size_t n);
描述:memmove() 函数从src内存中拷贝n个字节到dest内存区域,但是源和目的的内存可以重叠。
返回值:memmove函数返回一个指向dest的指针。
它和memcpy唯一区别就是在对待重叠区域的时候,memmove可以正确的完成对应的拷贝,而memcpy不能。
#include<stdio.h>
#include<string.h>
#include<assert.h>
void *my_memmove(void *dest, const void *str, int count)
{
char *pdest = (char *)dest;
const char *pstr = (char *)str;
assert(pdest);
assert(pstr);
if (pdest > pstr)
{
while (count--)
{
*(pdest + count) = *(pstr + count);
}
}
else
{
while (count--)
{
*pdest = *pstr;
pdest++;
pstr++;
}
}
return dest;
} int main()
{
int i = ;
int arr[] = { , , , , , , , , , };
my_memmove(arr + , arr + , * sizeof(int));
for (i = ; i < sizeof(arr) / sizeof(arr[]); i++)
{
printf("%d\n", arr[i]);
}
getchar();
return ;
}
赐教!
C语言库函数探究的更多相关文章
- C语言库函数--操作文件
//C库函数读取文件的代码 I/O缓冲机制 C语言库函数写文件都是写在内存中,然后一次写入磁盘.提高了效率. 读写文件,不对系统进行操作,一般采用C语言库函数.移植可以在任何可以对C支持的操作系统,而 ...
- C语言库函数大全及应用实例十四
原文:C语言库函数大全及应用实例十四 [编程资料]C语言库函数大全及应用实例十四 函数名: strset 功 能: 将一个串 ...
- C语言库函数大全及应用实例十三
原文:C语言库函数大全及应用实例十三 [编程资料]C语言库函数大全及应用实例十三 函数名: stat 功 能: 读取打 ...
- C语言库函数大全及应用实例十一
原文:C语言库函数大全及应用实例十一 [编程资料]C语言库函数大全及应用实例十一 函数名: setbkcolor 功 能 ...
- C语言库函数大全及应用实例十二
原文:C语言库函数大全及应用实例十二 [编程资料]C语言库函数大全及应用实例十二 函数名: setrgbpalette ...
- C语言库函数大全及应用实例十
原文:C语言库函数大全及应用实例十 [编程资料]C语言库函数大全及应用实例十 函数名: qsort 功 能: 使 ...
- C语言库函数大全及应用实例九
原文:C语言库函数大全及应用实例九 [编程资料]C语言库函数大全及应用实例九 函数名: mktemp 功 ...
- C语言库函数大全及应用实例八
原文:C语言库函数大全及应用实例八 [编程资料]C语言库函数大全及应用实例八 函数名: kbhit 功 能: 检查 ...
- C语言库函数大全及应用实例七
原文:C语言库函数大全及应用实例七 [编程资料]C语言库函数大全及应用实例七 函数名: getw 功 能: 从流中取一整数 用 法: int getw(FILE *strem); 程序例: #i nc ...
随机推荐
- 8.vue的生命周期
Vue实例有一个完整的生命周期,也就是从开始创建.初始化数据.编译模板.挂载Dom.渲染→更新→渲染.卸载等一系列过程,我们称这是Vue的生命周期.通俗说就是Vue实例从创建到销毁的过程,就是生命周期 ...
- SmartSql漫谈
最近在看smartSql源码,兄弟写的.写的很不错取取经. 记录下一些学习的东西,刚开始我先不系统的写了,随意一点哈,我看的差不多再给大家一个模块一个模块系统的写. public T ExecuteS ...
- 用Markdown优雅的写文章
简介 Markdown是一种可以使用普通文本编辑器编写的标记语言,通过简单的标记语法,它可以使普通文本内容具有一定的格式. 简单点来说,Markdown是文本标记语言,在普通文本的基础上加了一些特殊标 ...
- Cornerstone.js使用相关
官网地址:https://github.com/chafey/cornerstone 简介: Cornerstone is an open source project with a goal to ...
- Codeforces Round #418 (Div. 2).C two points
C. An impassioned circulation of affection time limit per test 2 seconds memory limit per test 256 m ...
- JavaScript一个拖动元素的实例
<script type="text/javascript" src="./whenReady.js"></script> <bo ...
- Python爬虫从入门到放弃(十五)之 Scrapy框架中Spiders用法
Spider类定义了如何爬去某个网站,包括爬取的动作以及如何从网页内容中提取结构化的数据,总的来说spider就是定义爬取的动作以及分析某个网页 工作流程分析 以初始的URL初始化Request,并设 ...
- 事务之使用JDBC进行事务的操作2
本篇将讲诉如何使用JDBC进行数据库有关事务的操作.在上一篇博客中已经介绍了事务的概念,和在MySQL命令行窗口进行开启事务,提交事务以及回滚事务的操作. 似乎事务和批处理都可以一次同时执行多条SQL ...
- CentOS-7.2安装Ambari-2.4.2
一,Ambari 是什么? Ambari 跟 Hadoop 等开源软件一样,也是 Apache Software Foundation 中的一个项目,并且是顶级项目.目前最新的发布版本是 2.4.2. ...
- 【转载】 ISO14229系列之一:简介
转载链接:http://www.cnblogs.com/autogeek/p/4458591.html 前言 由于工作中经常用到ISO-14229,因此决定对该协议做个总体介绍和总结,既是对自己学习的 ...