C语言-字符串函数和内存函数

字符串函数

字符串函数的标准库为

1. strlen函数

描述

strlen的功能是计算所给字符串str的长度,直到遇到空结束(即’\0’)字符,但不包含空结束字符。

声明

size_t strlen(const char*str)

这里的size_t,是指unsigned int类型,表明它返回的字符串长度是一个无符号整型的数值

模拟实现
size_t my_strlen(const char* str)
{
     
	size_t i = 0;//unsigned int 
	while (*str)
	{
     
		++str;
		++i;
	}
	return i;
}

2. strcpy函数

描述

strcpy的功能是把 src 所指向的字符串复制到 dest。但需要注意的是如果目标数组 dest 不够大,而源字符串的长度又太长,可能会造成内存缓冲溢出的情况。

声明

char *strcpy(char *dest, const char *src)

模拟实现
char* my_strcpy(char* str1, const char* str2)
{
     
	char* tmp = str1;
	while (*str1++ = *str2++);
	return tmp;
}

代码中 while (*str1++ = *str2++); 的含义是将 str2 所指向的值赋给 str1 所指向的值,然后str1和str2分别++,while循环判断的是 *str的值(即为左值)。

3. strcat函数

描述

strcat的功能是把 src 所指向的字符串追加到 dest 所指向的字符串的结尾。

声明

char *strcat(char *dest, const char *src)

模拟实现
//把src中的内容追加到dst的末尾,前提是dst的容量足够大。
//strcat实现时不用开辟新的空间
char* my_strcat(char* dst, const char* src) {
     
	char* tmp = dst;
	while (*dst) {
     //将指针指向dst的'\0'处
		dst++;
	}
	while (*dst++ = *src++); //将src中的内容赋值给dst
	return tmp;
}

4. strcmp函数

描述

strcmp的功能是把 str1 所指向的字符串和 str2 所指向的字符串进行比较,然后返回一个int类型的数值。

  • 如果返回值小于 0,则表示 str1 小于 str2。
  • 如果返回值大于 0,则表示 str1 大于 str2。
  • 如果返回值等于 0,则表示str1 等于 str2。
声明

int strcmp(const char *str1, const char *str2)

模拟实现
int my_strcmp(const char* str1, const char* str2)
{
     
	while (*str1 && *str2) {
     
		if (*str1 > *str2) {
      
				return 1;
			}
			else if(*str1<*str2){
     
				return -1;
			}
			else {
     
				str1++;
				str2++;
			}
	}
	if (*str1) {
     
		return 1;
	}
	else if (*str2) {
     
		return -1;
	}
	else {
     
		return 0;
	}
}

5. strstr函数

描述

strstr的功能是在字符串str中查找第一次出现字符串 sub的位置,不包含终止符 ‘\0’。该函数返回在str中第一次出现 sub字符串的位置,如果未找到则返回 null。

声明

char *strstr(const char *str, const char *sub)

模拟实现
char* my_strstr(const char* str, const char* sub)
{
     
	while (*str) {
      //首先遍历父串
		if (*str != *sub) {
      //如果不相等,则父串指针+1
			++str;
		}
		else {
      //如果首元素相等,则进行向后继续遍历,直到遇到'\0';
			char* p1 = str;
			char* p2 = sub;
			while (*p1 && *p2 && *p1 == *p2) {
     //向后遍历
				++p1;
				++p2;
			}
			if (*p1 == '\0') {
     //父串首先遍历完,说明不包含子串
				return NULL;
			}
			else if (*p2 == '\0')//子串首先遍历完,说明包含
			{
     
				return str;
			}
			else {
      //说明遍历过程中,出现不相等的情况
				++str;
			}
		}
	}
	return NULL;
}

内存函数

内存函数的标准库为

1. memcpy函数

描述

memcpy的功能是从存储区 str2 复制 size 个字节到存储区 str1。该函数返回一个指向目标存储区 str1 的指针。

声明

void *memcpy(void *str1, const void *str2, size_t size)

由于不知道传入的参数指向的内存是int类型(4Byte),还是char类型(1Byte),因此就用void来全部代替他们。

模拟实现
void* my_memcpy(void* dst, const void* src,size_t size)
{
     
	char* ch_dst = (char*)dst;
	char* ch_src = (char*)src;
	for (size_t i = 0;i < size;++i) {
     
		ch_dst[i] = ch_src[i];
	}
	return dst;
}

由于不知道这些参数所指向的内容的类型是什么,则统统将其强转为指向char类型的指针,因为char在内存中是1Byte,memcpy是从src复制size个Byte传给dst,因此不必担心改变类型后,结果的改变。

2. memmove函数

描述

memmove的功能和memcpy的功能基本一样,均是从 str2 复制 nsize个字节到 str1中。但是它可以解决内存重叠的问题,是一个比memcpy更安全的函数。

内存重叠

内存重叠,顾名思义,就是当进行内存拷贝时,拷贝的区间和原始的区间发生了重叠。举个例子:

int a[10] = {
      1,2,3,4,5 };
memcpy(a+4,a,20);

当上面的代码运行完后,a的值为1234123410。而我们期望的值为1234123450。这时候就发生了内存的重叠,a+4指向的是 5,从 5 这个元素的位置开始内存拷贝,首先会将5变为1,然后再继续向下按照a的指针进行赋值,而解决这种情况可以采取从后往前的赋值方式,首先赋值最后的元素,这样就可以得到我们预期的值1234123450。

内存重叠有3种情况:前重叠、后重叠、不重叠

  1. 前重叠

C语言-字符串函数和内存函数_第1张图片
从前向后的赋值即可

  1. 后重叠

C语言-字符串函数和内存函数_第2张图片
从后向前赋值即可

  1. 不重叠

C语言-字符串函数和内存函数_第3张图片
从前向后赋值即可

声明

void *memmove(void *str1, const void *str2, size_t size)

模拟实现
void* my_memmove(void* dst, const void* src, size_t size)
{
     
	//为了解决不知道大小的内存的拷贝(void),可以将其强转为char类型的,每次只拷贝一个字节,分多次拷贝即可
	char* ch_dst = (char*)dst;
	char* ch_src = (char*)src;
	//后重叠
	if (ch_dst >= ch_src && ch_dst <= ch_src + size)
	{
     
		//从后向前,注:这里不能用size_t来声明i,unsigned int为无符号整型,它是减不到0的,会造成for无限循环。
		for (int i = size - 1;i >= 0;--i) {
     
			ch_dst[i] = ch_src[i];
		}
	}
	else {
      //前重叠和不重叠的情况
		//从前至后,这时可以直接用size_t声明,不会造成无限循环
		for (size_t i = 0;i < size;++i) {
     
			ch_dst[i] = ch_src[i];
		}
	}
	return dst;
}

你可能感兴趣的:(C)