库函数模拟实现
1.模拟实现strlen(3种方法)
size_t strlen (const char* str)
1.字符串以’\0’结尾,strlen返回的是字符串内的\0之前的字符个数,遇见\0停止。
2.参数指向的字符串必须以’\0’结尾
3.它的返回值是size_t,也就是unsigned int ,取值范围为0-42亿
int main()
{
const char* str1="abcde";
const char* str2="bb"
if((strlen(str2)-strlen(str1)>0))
{
printf("str2>str1");
}
if((strlen(str2)-strlen(str1)<0))
{
printf("str1>str2");
}
}
以上程序按照常理应该说是str1>str2
但实际确是相反的。就像前面所说他是无符号整形所以永远不会出现负数的情况.
#include<stdio.h>
#include<windows.h>
#pragma warning(disable:4996)
//while(*str)与while(*str!='\0')与while(*str!=0)的区别
//效果相同,但是处理过程不一样
//while (*str)----将*str直接按逻辑值测试
//while (*str != '\0')----将*str与'\0'按char字符比较,再得逻辑值
//while (*str != 0)----将*str与0按int整数比较,再得逻辑值
//== == == == == == == == == == == ==
//编码规范要求用第二种形式
//计数器方法
int Strlen_1(const char *str)
{
int count = 0;
if (str == NULL)
{
return -1;
}
while (*str)
{
str++;
count++;
}
return count;
}
//递归,指针+1,往后移一次加一,不用创建临时变量计数器
int Strlen_2(const char *str)
{
if (str == NULL)
{
return -1;
}
if (*str == '\0')
{
return 0;
}
else
return 1 + Strlen_2(str + 1);
}
//指针-指针方法
int Strlen_3(char *str)
{
char *p = str;
while (*p)
{
p++;
}
return p - str;
}
int main(){
char *str = "abcd";
int ret=Strlen_1(str);
int re =Strlen_2(str);
int r = Strlen_3(str);
printf("%d %d %d", ret,re,r);
system("pause");
return 0;
}
2.模拟实现strcat
char *strcat (char *destination,const char *source)
源字符串以’\0’结尾。
目标空间必须足够大,能容纳字符串的所有内容
目标空间必须可修改
#include<stdio.h>
#include<windows.h>
#pragma warning(disable:4996)
char* Strcat( char* dest,const char* src)
{
char *ret = dest;
while (*dest)
{
dest++;
}
//src为const不过这里只是根据src的地址得到src的内容
//而dest如果为const的话就不能吧src的内容赋值到dest的空间里。
while ((*dest++=*src++))
{
;
}
//因为之前有dest已经发生变化,内容指向,u所以要定义一个ret指向l
return ret;
}
int main(){
//这里要用数组定义
char dest[100] = "love";
char* src = " you";
char* ret=Strcat(dest,src);
printf("%s", ret);
system("pause");
return 0;
}
3.模拟实现strcmp
#include<stdio.h>
#include<windows.h>
#include<assert.h>
#pragma warning(disable:4996)
int Strcmp(const char* dest, const char* src)
{
int ret = 0;
assert(src != NULL);
assert(dest != NULL);
while (!(ret=*(unsigned char*)dest - *(unsigned char*)src)&&*src)
{
src++;
dest++;
}
if (ret > 0)
{
return 1;
}
else if (ret < 0)
{
return -1;
}
return ret;
}
int main(){
char *dest = "abd";
char *src = "abcd";
int ret=Strcmp(dest, src);
printf("%d", ret);
system("pause");
return 0;
}
4.模拟实现strcpy
char *my_strcpy(char *dest, const char*src)
{
char *ret = dest;
assert(dest != NULL);
assert(src != NULL);
while((*dest++ = *src++))
{
;
}
return ret;
}
5.模拟实现strstr
char *my_strstr(const char* str1, const char* str2 )
{
assert(str1);
assert(str2);
char *cp = (char*)str1;
char *substr = (char *)str2;
char *s1 = NULL;
if(*str2 == '\0')
return NULL;
while(*cp)
{
s1 = cp;
substr = str2;
while(*s1 && *substr && (*s1 == *substr))
{
s1++;
substr++;
}
if(*substr == '\0')
return cp;
cp++;
}
}
6.模拟实现strcmp
#include<stdio.h>
#include<windows.h>
#include<assert.h>
#pragma warning(disable:4996)
int Strcmp(const char* dest, const char* src)
{
int ret = 0;
assert(src != NULL);
assert(dest != NULL);
while (!(ret=*(unsigned char*)dest - *(unsigned char*)src)&&*src)
{
src++;
dest++;
}
if (ret > 0)
{
return 1;
}
else if (ret < 0)
{
return -1;
}
return ret;
}
int main(){
char *dest = "abd";
char *src = "abcd";
int ret=Strcmp(dest, src);
printf("%d", ret);
system("pause");
return 0;
}
7.模拟实现memcpy
不会复制‘\0’
void * memcpy ( void * dst, const void * src, size_t count)
{
void * ret = dst;
assert(dst);
assert(src);
/*
* copy from lower addresses to higher addresses
*/
while (count--) {
*(char *)dst = *(char *)src;
dst = (char *)dst + 1;
src = (char *)src + 1;
}
return(ret);
}
8.模拟实现memove
可能会有内存重叠情况
#include<stdio.h>
#include<windows.h>
#pragma warning(disable:4996)
void *Memove(void *dest, const void *src, int num)
{
char* _dest = dest;
const char* _src = src;
//从右向左拷贝,dest>src且有交集
if (_dest > src&&_dest < _src + num)
{
_dest = _dest + num - 1;
_src = _src + num - 1;
while (num)
{
_dest--;
_src--;
num--;
}
}
//剩余的就三种情况从左向右完全可以拷贝
else
{
while (num)
{
*_dest = *_src;
_dest++;
_src++;
num--;
}
}
}
int main(){
char str[] = "love you";
char arr[] = " ";
Memove(arr,str,strlen(str)+1);
printf("%s", str);
system("pause");
return 0;
}
9.内存操作函数与字符串操作函数区别
字符串操作函数:
函数名: strcpy
功 能: 将参数src字符串拷贝至参数dest所指的地址
用 法: char *strcpy(char *dest, constchar *src);
返回值: 返回参数dest的字符串起始地址
如果参数dest所指的内存空间不够大,可能会造成缓冲溢出的错误情况,在编写程序时需特别留意,或者用strncpy()来取代.
函数名: strncpy
功 能:将字符串src前n个字符拷贝到字符串dest
用 法: char *strncpy(char *dest, constchar *src, size_t n);
返回值: 返回参数dest的字符串起始地址
说 明: 不像strcpy(),strncpy()不会向dest追加结束标记’\0’;
src和dest所指的内存区域不能重叠,且dest必须有足够的空间放置n个字符;
函数名: strcat
功 能: 字符串拼接函数
用 法: char *strcat(char *dest, constchar *src);
返回值: 返回dest字符串起始地址
说 明: strcat() 会将参数src字符串复制到参数dest所指的字符串尾部;
dest最后的结束字符’\0’会被覆盖掉,并在连接后的字符串的尾部再增加一个’\0’;
dest与src所指的内存空间不能重叠,且dest要有足够的空间来容纳要复制的字符串;
函数名: strncat
功 能:将n个字符追加到字符串的结尾
用 法: char *strncat(char *dest, constchar *src, size_t n);
返回值: 返回dest字符串起始地址
说 明: strncat()将会从字符串src的开头拷贝n个字符到dest字符串尾部,dest要有足够的空间来容纳要拷贝的字符串;
如果n大于字符串src的长度,那么仅将src全部追加到dest的尾部;
strncat()会将dest字符串最后的’\0’覆盖掉,字符追加完成后,再追加’\0’;
函数名: strcmp
功 能:字符串比较, 区分大小写
用 法: intstrcmp(constchar *s1, constchar *s2);
返回值: 根据ASCII码比较,若参数s1和s2字符串相同则返回0,s1若大于s2则返回大于0的值,s1若小于s2则返回小于0的值
说 明: 它是区分大小写比较的,如果希望不区分大小写进行字符串比较,可以使用stricmp函数
函数名: stricmp
功 能:比较字符串s1和s2,但不区分字母的大小写。
说 明:strcmpi是到stricmp的宏定义,实际未提供此函数。
当s1<s2时,返回值<0
当s1=s2时,返回值=0
当s1>s2时,返回值>0
内存操作函数:
名称:memcpy
功能:拷贝内存空间
头文件:#include <stdlib.h>
函数原型:void memcpy(voiddest, void *src, size_t n);
其中:dest为目标内存区,src为源内存区,n为需要拷贝的字节数
返回值:指向dest的指针
局限性:未考虑内存重叠情况(但其实这个问题已经得以解决)
区别:
strcpy和memcpy主要有以下3方面的区别:
1、复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。
2、复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符"\0"才结束,所以容易溢出。memcpy则是根据其第3个参数决定复制的长度。
3、用途不同。通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy
名称:memmove
功能:拷贝(移动)内存空间
头文件:#include <stdlib.h>
函数原型:void memmove(voiddest, void *src, size_t n);
其中:dest为目标内存区,src为源内存区,n为需要拷贝的字节数
返回值:指向dest的指针
相比memcpy:当dest与src重叠时,仍能正确处理,但是src内容会被改变