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)

(1)模式匹配是数据结构中字符串的一种基本运算,给定一个子串,要求在某个字符串中找出与该子串相同的所有子串,这就是模式匹配。
假设str是给定的子串,substr是待查找的字符串,要求从str中找出与substr相同的所有子串,这个问题成为模式匹配问题。str称为模式,substr称为目标。如果str中存在一个或多个模式为substr的子串,就给出该子串在str中的位置,称为匹配成功;否则匹配失败。
这种匹配方法可以解决问题,但是并不高效,最坏的情况下要匹配M*(N-M+1)次,时间复杂度为O(M*N)。比如下面的例子:
char str = "ababcababa";
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的指针。

2.如果目标数组destin本身已有数据,执行memcpy()后,将覆盖原有数据(最多覆盖n)。如果要追加数据,则每次执行memcpy后,要将目标数组地址增加到你要追加数据的地址。
注意:source和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语言库函数探究的更多相关文章

  1. C语言库函数--操作文件

    //C库函数读取文件的代码 I/O缓冲机制 C语言库函数写文件都是写在内存中,然后一次写入磁盘.提高了效率. 读写文件,不对系统进行操作,一般采用C语言库函数.移植可以在任何可以对C支持的操作系统,而 ...

  2. C语言库函数大全及应用实例十四

    原文:C语言库函数大全及应用实例十四                                       [编程资料]C语言库函数大全及应用实例十四 函数名: strset 功 能: 将一个串 ...

  3. C语言库函数大全及应用实例十三

    原文:C语言库函数大全及应用实例十三                                          [编程资料]C语言库函数大全及应用实例十三 函数名: stat 功 能: 读取打 ...

  4. C语言库函数大全及应用实例十一

    原文:C语言库函数大全及应用实例十一                                         [编程资料]C语言库函数大全及应用实例十一 函数名: setbkcolor 功 能 ...

  5. C语言库函数大全及应用实例十二

    原文:C语言库函数大全及应用实例十二                                          [编程资料]C语言库函数大全及应用实例十二 函数名: setrgbpalette ...

  6. C语言库函数大全及应用实例十

    原文:C语言库函数大全及应用实例十                                             [编程资料]C语言库函数大全及应用实例十 函数名: qsort 功 能: 使 ...

  7. C语言库函数大全及应用实例九

    原文:C语言库函数大全及应用实例九                                                [编程资料]C语言库函数大全及应用实例九 函数名: mktemp 功 ...

  8. C语言库函数大全及应用实例八

    原文:C语言库函数大全及应用实例八                                            [编程资料]C语言库函数大全及应用实例八 函数名: kbhit 功 能: 检查 ...

  9. C语言库函数大全及应用实例七

    原文:C语言库函数大全及应用实例七 [编程资料]C语言库函数大全及应用实例七 函数名: getw 功 能: 从流中取一整数 用 法: int getw(FILE *strem); 程序例: #i nc ...

随机推荐

  1. JavaScript深入之从原型到原型链(本文转载)

    JavaScript深入之从原型到原型链(本文转载) https://github.com/mqyqingfeng/Blog.原文地址 构造函数创建对象 我们先使用构造函数创建一个对象: functi ...

  2. NEWS-包名-baseTest-类名-ConfigManager

    package baseTest; import java.io.IOException;import java.io.InputStream;import java.util.Properties; ...

  3. 第一篇:webservice初探

    接触webservice也有一段时间了,为了查缺补漏,把知识点系统化,准备写几篇博文梳理下webservice的知识点,这是第一篇,对webservice进行大致的介绍. 1.什么是webservic ...

  4. FreeRTOS——内存管理

    1. 标准malloc() 和 free() 库函数的缺陷: 1)在小型的嵌入式系统中,可能不可用. 2)具体实现相对较大,占用较多宝贵的代码空间. 3)通常不具备线程安全性. 4)具有不确定性,每次 ...

  5. nyoj_68:三点顺序(计算几何)

    题目链接 根据 AB*AC的值进行判断即可(ps,结果为0时不构成三角形) #include<iostream> #include<cstdio> #include<cs ...

  6. 途虎养车Tuhu商城系统开发

    途虎养车Tuhu商城系统开发,咨询:何经理152-2217-7508(微信同号)途虎养车商城小程序开发,途虎养车商城小程序平台开发,途虎养车商城小程序系统开发. 为什么能做得这么好,里面的门道确实不少 ...

  7. JAVA 笔记 ClassLoader.getResourceAsStream() 与 Class.getResourceAsStream()的区别

       Class.getResourceAsStream() 会指定要加载的资源路径与当前类所在包的路径一致. 例如你写了一个MyTest类在包com.test.mycode 下,那么MyTest.c ...

  8. Loadrunner常用15种的分析点

    性能测试的工具目前用的最多的就是LoadRunner和JMeter,性能测试重点在分析和解决, 下边列出了LR中常见的15种分析点,不知道如何分析性能,来看这里吧! Vusers:提供了生产负载的虚拟 ...

  9. select可选择、同时可自行输入

    HTML部分: <li class="bl-form-group"> <label>诊断医生</label> <div class=&qu ...

  10. struts加载spring

    为了在Struts中加载Spring context,需要在struts-config.xml文件中加入如下部分: <struts-config> <plug-in classNam ...