strncpy、strncat、strncmp函数的使用说明和模拟实现

在前面的文章中,我已经介绍了长度不受限制的字符串函数。今天我来介绍几个长度受限制的字符串函数,并且模拟实现这些长度受限制的字符串函数。





strncpy函数

strncpy函数也是一个拷贝函数,但是与strcpy函数有所不同,strncpy函数是从源字符串拷贝num个字符到目标字符串,num是strncpy函数的一个参数,当源字符串的字符数目小于num时,在拷贝完源字符串后,会在目标字符串中追加0,直到达到num的数目。
请添加图片描述
由msdn查询可以得知,strncpy函数的返回值和参数是:
char* strncpy(char* destination,const char* source,size_t num)。注意我们只关注返回类型和参数的类型,参数的名字不管。

接着,继续往下查询strncpy函数的返回值。
请添加图片描述
由msdn对strncpy的返回值的介绍可知,strncpy函数返回目标字符串的地址。

接下来,我来举一个strncpy函数的使用例子。

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[20] = "abcdef";
	char arr2[] = "xxxxxx";
    printf("%s\n",strncpy(arr1,arr2,5));
    return 0;
}

请添加图片描述
由运行结果可以知道,strncpy函数确实从源字符串拷贝num个字符到目标字符串。

接下来,我来验证一下strncpy函数的拷贝过程中,源字符串达不到num个字符,那么就会在拷贝完源字符串后,在目标字符串后面补0,直到达到num个字符。

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[20] = "abcdefhij";
	char arr2[] = "xxxx";
    printf("%s\n",strncpy(arr1,arr2,8));
    return 0;
}

在strncpy函数拷贝前,arr1的内容如下:
请添加图片描述

在strncpy函数拷贝后,arr1的内容如下:
请添加图片描述
在该程序中,arr2中有4个字符,而strncpy函数却要从arr2中拷贝8个字符到arr1,按照源字符串不足拷贝时,要在源字符串拷贝后补0,那么就要补4个0。由图片可以得知,arr1确实被覆盖了arr1的内容和4个0。

接下来,我来实现strncpy函数的模拟实现。

#include<stdio.h>
#include<assert.h>
#include<string.h>
char* my_strncpy(char* dest,const char* src,size_t len)
{
	char* ret = dest;
    int offset = 0;
	assert(dest != NULL);
	assert(src != NULL);
	if(strlen(src) < len)
	{
	    offset = len - strlen(src);
		len = strlen(src);
	}
	while(len)
	{
	    *dest++ = *src++;
		len--;
	}
	while(offset)
	{
	    *dest++ = '\0';
		offset--;
	}
	return ret;
}
int main()
{
	char arr1[20] = "abcdef";
	char arr2[] = "xxxx";
	my_strncpy(arr1,arr2,3);
	printf("%s\n",arr1);
    return 0;
}

请添加图片描述
由图片可以知道,该模拟实现函数可以满足strncpy函数的要求。



strncat函数

strncat函数与strcat函数功能差不多相同,唯一有区别的是strncat函数是追加count个字符(count是strncat函数的参数),而strcat是将整个字符数组追加到另一个字符数组。

请添加图片描述
由msdn查询可知,strncat函数的返回类型和参数类型是:
char* strncat(char* dest,const char* src,size_t num),注意,我们只关注返回类型和参数类型,不关注参数名字。
请添加图片描述
在msdn继续查询可以得知,strncat函数的返回值是目标字符串的地址。(注意这里是返回值,跟上面的返回类型有所不同)

现在,我来举一个strncat函数的使用例子。

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[20] = "abcdef"; 
	char arr2[] = "xyz";
	printf("%s\n",strncat(arr1,arr2,2));
    return 0;
}

请添加图片描述
接下来,我来写一个小程序,观察一下strncat函数的更多的细节。

#include<string.h>
int main()
{
	char arr1[20] = "abcdef\0qqqqqqqqqqqq";
	char arr2[] = "xyz";
	strncat(arr1,arr2,2);
    return 0;
}

这是arr1开始时存储的内容:请添加图片描述

这是arr1数组被追加时的内容:

请添加图片描述

对比一下arr1被拷贝前和被拷贝后的变化可以发现,strncat还是从’\0’开始覆盖,并且覆盖完后对应的几个字符后,开始在后面加个’\0’。

在上一篇文章中,我已经验证过strcat函数不能用在字符串自己给自己追加,那么与strcat函数功能差不多的是strncat函数,能不能用在字符串自己给自己追加呢?

我用小程序来验证一下。

#include<string.h>
int main()
{
	char arr1[20] = "abc";
	strncat(arr1,arr1,3);
    return 0;
}

arr1被追加字符前:
请添加图片描述

这是arr1被追加后:
请添加图片描述

由调试过程中的观察可以得知,strncat的确实现了字符自己给自己追加,我来分析一下成功的原因所在。

在前面文章提到的strcat函数不能用在字符串自己给自己追加的原因是’\0’被覆盖掉,而strcat函数是以从源字符串拷贝到’\0’去到目标字符串作为停止条件,而’\0’却在拷贝的过程中被覆盖掉,那么strcat函数就会持续的拷贝,进入到死循环拷贝。

与strcat函数不同的是,strncat函数是以拷贝完想要拷贝的字符字数(即给strncat函数传参的数字)作为结束标志,并且在拷贝完成的目标字符串后面再添加个’\0’,注意的是,这个’\0’不是从源字符串中拷贝过来的,strncat函数自己添加的,那么,即使arr1中的’\0’早早的就被覆盖掉,也不会影响strncat函数的正常运作。

接下来,我来模拟实现strncat函数。

#include<stdio.h>
#include<assert.h>
char* my_strncat(char* dest,const char* src,size_t num)
{
    char* ret = dest;
	assert(dest != NULL);
	assert(src != NULL);
	while(*dest != '\0')        //找到'\0'的位置
	{
	    dest++;
	}
	while(num--)                //开始往目标字符串追加字符
	{
	    *dest++ = *src++;
	}
	*dest = '\0';               //最后覆盖'\0'
	return ret;
}
int main()
{
	char arr1[20] = "abcdef";
	char arr2[] = "abcdef";
	printf("%s\n",my_strncat(arr1,arr2,5));
    return 0;
}

请添加图片描述
由运行结果可以发现该模拟实现strncat函数确实满足了我们的要求。



strncmp函数

strncmp函数与strcmp函数都是字符串比较函数,有区别的是strncmp只是比较调用该函数时传参的num个字符,那么我依然来介绍一下该函数的返回类型和参数类型,还有返回值吧。

请添加图片描述
在msdn查询可以得知,strncmp函数的参数类型和返回类型是:int strncmp(const char* str1,const char* str2,size_t num),与strcmp函数参数类型和返回类型相比,只是多了个参数。

接下来,我来介绍一下该函数的返回值。
请添加图片描述
1.第一个字符串小于第二个字符串,返回小于0的数字。
2.第一个字符串等于第二个字符串,返回等于0的数字。
3.第一个字符串大于第二个字符串,返回大于0的数字。

接下来,我来举一个strncmp函数的使用例子。

#include<stdio.h>
#include<string.h>
int main()
{
    char arr1[20] = "abcdefghi";
	char arr2[] = "abcdef";
	printf("%d\n",strncmp(arr1,arr2,6));
	return 0;
}

运行结果如下:
请添加图片描述
观察arr1和arr2的字符数组可以得知两者根本不一样,但是我们只想比较前6个字符是否不一样,所以就给strncmp函数传参传6,结果返回了0,也就是前6个元素是一样的。

接下来,我来模拟实现strncmp函数。

#include<stdio.h>
#include<assert.h>
int my_strncmp(const char* str1,const char* str2,size_t num)
{
	assert(str1 != NULL);
	assert(str2 != NULL);
    while(num--)
	{
	    if(*str1 == *str2)
		{
		    str1++;
			str2++;
		}
		else
		{
		    if(*str1 > *str2)
			{
				return 1;
			}
			else
			{
			    return -1;
			}
		}
	}
	return 0;
}
int main()
{
    char arr1[] = "abcdef"; 
	char arr2[] = "abcdefghijk";
	printf("%d\n",my_strncmp(arr1,arr2,6));
	return 0;
}

运行结果如下:
请添加图片描述
该模拟实现strncmp函数确实满足了我们的要求。

今天,我对于长度受限制的字符串函数已经介绍完了,而字符串函数的还多着,关注点一点,下期继续学字符串函数。