【C语言】字符和字符串的库函数及模拟实现

           

目录

1. 求字符串长度

     strlen

2. 长度不受限制的字符串函数

     strcpy

     strcat

     strcmp

3. 长度受限制的字符串函数

     strncpy

     strncat

     strncmp

4. 字符串查找

     strstr

     strtok

5. 内存操作函数

            memcpy

   memmove

   memset




        

1. 求字符串长度

     strlen

      

      字符串已经 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不         包含 '\0' )。

      参数指向的字符串必须要以 '\0' 结束

    ●  函数的返回值为size_t,是无符号的

使用如下:

#include 
#include 

int main()
{
	char str[] = "abcde";
	printf("%u\n", strlen(str));
	return 0;
}

模拟实现:

① 计数方式

#include 

size_t my_strlen(const char* str)
{
	int count = 0;
	while (*str++)
		count++;
	return count;
}

int main()
{
	size_t sz = my_strlen("abcde");
	printf("%u\n", sz);
	return 0;
}

注意:返回值size_t为无符号数

② 递归方式

int my_strlen(const char* str)
{
	if (*str == '\0')
		return 0;
	else
		return 1 + my_strlen(str + 1);
}

③指针-指针方式

int my_strlen(char* str)
{
	char* p = str;
	while (*p != '\0')
		p++;
	return p - str;
}


 

2. 长度不受限制的字符串函数

     strcpy

  

       指向的 C 字符串复制到目标指向的数组中,包括终止的 null 字符(并在该点停止)。
为避免溢出,目标指向的数组的大小应足够长,以包含与相同的 C 字符串(包括终止空字符),并且不应在内存中与重叠。

       ●   源字符串必须以 '\0' 结束

       ●   会将源字符串中的 '\0' 拷贝到目标空间

       ●   目标空间必须足够大且是可变的,以确保能存放源字符串

       ●   不应在内存中与重叠

使用如下:

#include 
#include 

int main()
{
	char arr1[10] = "abcdefg";
	char arr2[] = "xxxxx";
	strcpy(arr1, arr2);
	printf("%s\n", arr1);

	return 0;
}

模拟实现

   

#include 
#include 

char* my_strcpy(char* dest, const char* src)
{
	assert(dest && src);
	char* ret = dest;
	while (*src)
	{
		*dest = *src;
		dest++;
		src++;
	}
	*dest = *src; //复制“\0”
	//或
	/*while (*dest++ = *src++)
	{
		;
	}*/
	return ret;
}

int main()
{
	char arr1[10] = "abcdefg";
	char arr2[] = "xxxxx";
	my_strcpy(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

注意:源字符串中的“\0”,也要拷贝到目标串

 strcat

      

       字符串的副本追加到目标字符串。目标中的终止空字符("\0")的第一个字符覆盖,并且在目标中由两者串联形成的新字符串的末尾包含一个空字符目标串源串不得重叠

            源字符串必须以 '\0' 结束

         ●   目标空间必须有足够的大,能容纳下源字符串的内容

         ●   目标空间必须可修改 

         ●   目标串源串不能重叠
         

使用如下:

#include 
#include 

int main()
{
	char arr1[20] = "hello ";
	char arr2[] = "world";
	strcat(arr1, arr2);

	printf("%s\n", arr1);

	return 0;
}

模拟实现

   

#include 
#include 

char* my_strcat(char* dest, const char* src)
{
	assert(dest && src);
	char* ret = dest;//保存目标串的首地址
    //找目标串中的空字符"\0"
	while (*dest)
		dest++;
    //连接
	while (*dest++ = *src++)
	{
		;
	}
	return ret;
}

int main()
{
	char arr1[20] = "hello ";
	char arr2[] = "world";
	my_strcat(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

strcmp

     

       将 C 字符串 str1 与 C 字符串 str2 进行比较。此函数开始比较每个字符串的第一个字符。如果它们彼此相等,则继续往下比较,直到字符不同或达到终止空字符。

         返回值  :

    【C语言】字符和字符串的库函数及模拟实现_第1张图片

 使用如下:

   

#include 
#include 

int main()
{
	char arr1[] = "bbq";
	char arr2[] = "bcq";
	printf("%d\n", strcmp(arr1, arr2));//arr1中b比c小,故返回小于零的数

	return 0;
}

模拟实现:

#include 
#include 

int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);
	while (*str1 == *str2)
	{
		if (*str1 == '\0')
			return 0;
		str1++;
		str2++;
	}
	return *str1 - *str2;//返回的是小于0或大于0的值
}

int main()
{
	int ret = my_strcmp("bbq", "bcq");
	printf("%d\n", ret);
	return 0;
}

注意:返回值应写成两字符的差的形式,这样返回的才是小于0或大于0的数字


     

 说明:vs编译器返回值为1(大于0时)、-1(小于0时)、0(等于0时),不同编译器或许会有所不同

3. 长度受限制的字符串函数

      strncpy

   

      的第一个字符数复制到目标。如果在复制 num 个字符之前找到 C 字符串的末尾(由 null 字符表示),则目标将填充零,直到总共写入 num 个字符为止。如果长度超过 num则不会在目标末尾隐式附加空字符,因此,在这种情况下,不应将目标视为以空结尾的 C 字符串(这样读取它会溢出)目标串源串不得重叠(有关重叠时更安全的替代方案,请参见 Memmove)。 

             ●  拷贝num个字符从源字符串到目标空间

             ●  如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到                       num个

             ●  目标串源串不能重叠

使用如下:

    【C语言】字符和字符串的库函数及模拟实现_第2张图片

模拟实现:

    

#include 
#include 

char* my_strncpy(char* dest, const char* src, size_t num)
{
	assert(dest && src);
	char* ret = dest;//保存目标串的首地址
	while (num-- && (*dest++ = *src++))
	{
		;
	}
    //补超出的num个"\0"
	while (num--)
		*dest++ = '\0';
	return ret;
}


int main()
{
	char arr1[20] = "abcdef";
	char arr2[] = "xxx";
	my_strncpy(arr1, arr2, 2);
	printf("%s\n", arr1);
	return 0;
}

    strncat

     

           的第一个数字字符追加到目标外加一个终止空字符如果中 C 字符串的长度小于 num,则仅复制终止空字符之前的内容

使用如下:

     注意: num无论小于或大于源串长度,结尾的 "\0" 都是外加的终止符,strncat函数仅复        制"\0"之前的字符

【C语言】字符和字符串的库函数及模拟实现_第3张图片

 

模拟实现:

   

#include 
#include 

char* my_strncat(char* dest, const char* src, size_t num)
{
	assert(dest && src);
	char* ret = dest;
	while (*dest)
		dest++;
	while (num && *src)
	{
		*dest = *src;
		dest++;
		src++;
		num--;
	}
	*dest = '\0'; //额外附加"\0";strncat只连接源串中空字符之前的字符
	return ret;
}

int main()
{
	char arr1[20] = "abcdef";
	char arr2[] = "xxxxxx";
	my_strncat(arr1, arr2, 8);
	printf("%s\n", arr1);
	return 0;
}


   strncmp

    

       将 C 字符串 str1 的字符数与 C 字符串 str2 的字符进行比较。此函数开始比较每个字符串的第一个字符。    如果它们彼此相等,则继续使用以下对,直到字符不同,直到达到终止的空字符,或者直到两个字符串中的 num 字符匹配,以先发生者为准.

         ●  比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完

返回值:

           【C语言】字符和字符串的库函数及模拟实现_第4张图片

使用如下:

        

#include 
#include 

int main()
{
	char arr1[] = "abcqwertyuio";
	char arr2[] = "abcpef";
	printf("%d\n", strncmp(arr1, arr2, 4));

	return 0;
}

 

模拟实现:

      

#include 
#include 

int my_strncmp(const char* str1, const char* str2, size_t num)
{
	assert(str1 && str2);
	//没有字符比较
	if (!num)
		return 0;
	//当字符相等且不为'\0'时比较下一个字符
	while (num-- && *str1 && (*str1 == *str2))
	{
		str1++;
		str2++;
	}
	return *str1 - *str2;
}

int main()
{
	char arr1[] = "abcqwertyuiop";
	char arr2[] = "abcdef";
	int ret = my_strncmp(arr1, arr2, 4);
	printf("%d\n", ret);
	return 0;
}

    

4. 字符串查找


     strstr

         

         返回指向 str2 中第一次出现的 str1 的指针,如果 str2 不是 str1 的一部分,则返回一个空指针。匹配过程不包括终止空字符,但它到此为止。

使用如下:

          

#include 
#include 

int main()
{
	char arr1[] = "abbbcdef";
	char arr2[] = "bbc";
	char* ret = strstr(arr1, arr2);
	if (ret != NULL)
		printf("%s\n", ret);
	else
		printf("找不到\n");

	return 0;
}

  

模拟实现:

        

#include 

char* my_strstr(char* str1, char* str2)
{
	char* cp = str1;
	char* s1 = cp;
	char* s2 = str2;
    //判断源字符串是否为空串
	if (*str2 == '\0')
		return str1;
    //匹配不成功时把cp指针赋给s1让s1指针往后走
	while (*cp)
	{
		s1 = cp;
		s2 = str2;
        //匹配
		while (*s1 && *s2 && *s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
			return cp;
		cp++;
	}
	return NULL;
}

int main()
{
	char arr1[] = "abbbcdef";
	char arr2[] = "bbc";
	
	char* ret = my_strstr(arr1, arr2);
	if (ret != NULL)
		printf("%s\n", ret);
	else
		printf("找不到\n");
	return 0;
}


  strtok

       

                delimiter参数是个字符串,定义了用作分隔符的字符集合
                第一个参数指定一个字符串,它包含了0个或者多个由delimiter字符串中一个或者多个                    分隔符分割的标记

             ●   strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针                    (注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都                               是 临时拷贝的内容并且可修改。)
             ●   strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保                      存 它在字符串中的位置

             ●   strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始                      找 下一个标记

                如果字符串中不存在更多的标记,则返回 NULL 指针

     使用如下:

              

#include 
#include 

int main()
{
	char arr[] = "[email protected]@666#777";
	char copy[30]; //为了源串不被修改,提前备份
	strcpy(copy, arr);
	
	char delimiter[] = "@.#";
	char* ret = NULL;
	
	for (ret = strtok(copy, delimiter); ret != NULL; ret=strtok(NULL, delimiter))
	{
		printf("%s\n", ret);
	}

	return 0;
}

【C语言】字符和字符串的库函数及模拟实现_第5张图片

 知道会用即可

5. 内存操作函数

    memcpy

            

       将字节的值从指向的位置直接复制到目标指向的内存块。指针和目标指针指向的对象的基础类型与此函数无关;结果是数据的二进制副本。该函数不检查中的任何终止空字符 - 它总是准确地复制字节。为避免溢出,目标参数指向的数组大小应至少为字节,并且不应重叠(对于重叠的内存块,memmove 是一种更安全的方法)

        

              函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位                    置

            ●  这个函数在遇到 '\0' 的时候并不会停下来

            ●  如果source和destination有任何的重叠,复制的结果都是未定义的,即不应重

使用如下:

            此函数可拷贝不同类型的数据,此处以int型为例

         

#include 
#include 

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[20] = { 0 };
	//将arr1中的内容,拷贝到arr2中
	memcpy(arr2, arr1, 40);
	int i = 0;
	for (i = 0; i < 20; i++)
	{
		printf("%d ", arr2[i]);
	}

	return 0;
}

模拟实现:

      

//函数拷贝结束后,返回目标空间的起始地址
void* my_memcpy(void* dest, const void* src, size_t num)
{
	
	assert(src && dest);
    void* ret = dest;
	while (num--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };

	int arr2[20] = { 0 };
	my_memcpy(arr2, arr1, 20);
	int i = 0;
	for (i = 0; i < 20; i++)
	{
		printf("%d ", arr2[i]);
	}
	return 0;
}

 memmove

          

       将字节的值从指向的位置复制到目标指向的内存块。复制就像使用了中间缓冲区一样,允许目标重叠指针和目标指针指向的对象的基础类型与此函数无关;结果是数据的二进制副本。该函数不检查中的任何终止空字符 - 它总是准确地复制字节。为避免溢出,目标参数和参数指向的数组的大小应至少为字节。 

             ●  和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的

             ●  如果源空间和目标空间出现重叠,就得使用memmove函数处理

 使用如下

           

#include 
#include 

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	//把3 4 5 6 7拷贝到1 2 3 4 5
	memmove(arr1, arr1+2, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}

	return 0;
}

模拟实现:

    图解:        【C语言】字符和字符串的库函数及模拟实现_第6张图片

              

#include 
#include 

void* my_memmove(void* dest, const void* src, size_t num)
{
	assert(dest && src);
	char* ret = dest;
	if (dest < src)
	{
		//从前往后拷贝(包括不重叠)
		while (num--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else
	{
		//从后往前拷贝
		while (num--)
		{
			*((char*)dest + num) = *((char*)src + num);
		}
	}
	return ret;
}

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memmove(arr1+2, arr1, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

  memset

           

          填充内存块,将 ptr 指向的内存块的第一个字节设置为指定

ptr           指向要填充的内存块的指针

value      要设置的值。该值作为 int 传递,但该函数使用此无符号 char 转换填充内存块

num        要设置为该值的字节数
 

使用如下:

        

#include 
#include 

int main()
{
	char arr[] = "hello bit";
	memset(arr+1,'x',4);//以字节为单位设置
	printf("%s\n", arr);
	return 0;
}


你可能感兴趣的:(c语言,开发语言)