C标准库<string.h>库函数详解与模拟实现

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[] = "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

#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[] = "love";
	char* src = " you";
	char* ret=Strcat(dest,src);
	printf("%s", ret);
    system("pause");
	return 0;
}

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的字符串起始地址

扫描二维码关注公众号,回复: 12480807 查看本文章

如果参数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内容会被改变

猜你喜欢

转载自blog.csdn.net/qq_45928272/article/details/109901193