上次发布了长度不受限制的字符串函数的模拟实现方法,这次就给大家说说长度受限制的字符串函数。首先,长度受限制和不受限制有什么区别呢?其实从某种意义上来讲,长度受限制的字符串函数比长度不受限制的字符串安全,为什么安全呢?下面就让我们看看长度受限制的字符串函数到底在哪安全了,安全到哪了,
1.strncpy
首先来看这个函数的前两个参数都不用说(如果有不懂的小伙伴可以看我上一篇博客),第三个参数的意思是拷贝几个字符,返回类型就不用说了吧,直接看库里面函数的代码以及调试过程以及打印:
//int main()
//{
// char arr[] = "abcdef";
// char arr1[20] = "xxxxxxxxxxxxxx";
// char* p = strncpy(arr1, arr, 12);
// printf("%s", p);
// return 0;
//}
其实仔细观察,你会发现我们要拷贝的字符个数大于了要拷贝字符串的长度,那么,大家想想,会发生什么,我们看到调试的时候已经拷贝完成,但是拷贝完成之后,多余的那些字符怎么办呢?其实,再用strncpy时,多余的字符会用‘\0’来代替。
那么我们看一下我们自己模拟实现的这个函数到底与库函数的功能项不相同呢?看下面:
char* my_strncpy(char* dest, const char* src, size_t num)
{
assert(dest && src);
char* tem = dest;
while (num)
{
if (*src != '\0')
{
*dest++ = *src++;
num--;
}
else
{
*dest++ = '\0';
num--;
}
}
return tem;
}
int main()
{
char arr[] = "abcdef";
char arr1[20] = "xxxxxxxxxxxxxxxxx";
char* p = my_strncpy(arr1, arr, 12);
printf("%s", p);
return 0;
}
我们可以看到的是我们模拟实现的这个函数功能与库里的函数功能相同,调试过程也是相同的,多余字符用了‘\0’来代替。这个函数的注意事项和strcpy的一样,就不在这里多说了,而我想说说他与strcpy的区别是:首先,strcpy是拷贝整个字符串,不受长度限制,只要使用,就是整个字符串拷贝,而strncpy是受字符串长度限制的,他一般是会看第三个参数是几就拷贝几个字符过去,所以这个要注意,如果要是拷贝的字符个数小于源头字符串的长度的话,拷贝完之后是不加‘\0’的,举个例子:
char* my_strncpy(char* dest, const char* src, size_t num)
{
assert(dest && src);
char* tem = dest;
while (num)
{
if (*src != '\0')
{
*dest++ = *src++;
num--;
}
else
{
*dest++ = '\0';
num--;
}
}
return tem;
}
int main()
{
char arr[] = "abcdef";
char arr1[20] = "xxxxxxxxxxxxxxxxx";
char* p = my_strncpy(arr1, arr, 3);
printf("%s", p);
return 0;
}
就用我们自己实现的这个函数来写举例子吧,如果拷贝的字符数是3个,那么此时的arr1打印出来是这个结果
充分说明了在拷贝的时候没有加‘\0’,说几个就是几个。
2.strncat
这个函数的返回类型,形参与上面相同,就不在多说,他的功能是追加字符串,先上代码理解一下这个函数。
int main()
{
char arr[100] = "hello xxxxxxxxxx";
char arr1[] = "world";
strncat(arr, arr1, 4);
printf("%s", arr);
return 0;
}
要注意的是这个函数在追加完限制的长度后,会自动加上\0,这个是与strcat不同的,下面我们来自己实现一下这个函数,
char* my_strcat(char* dest, const char* src, size_t num)
{
assert(dest && src);
char* tem = dest;
while (*dest++);
dest--;
while (num)
{
if (*src)
{
*dest++ = *src++;
num--;
}
else
{
break;
}
}
*dest = '\0';
return tem;
}
int main()
{
char arr[20] = "hello \0xxxxxxx";
char arr1[] = "world";
char* p = my_strcat(arr, arr1, 4);
printf("%s", p);
return 0;
}
这个结果与我们想要的看到的结果正是一样的,如果要追加长度大于我们圆头的字符串,那么就把整个源头字符串追加上去就好,多余的不会像strncpy一样补'\0',感兴趣的可以自己测试一下,这个函数的注意事项与strcat也是基本一样,这里就不再多说。
3.strncmp
这个函数与strcmp的参数与返回类型一样,这里不再多说,这个函数的功能就是对比字符串的大小,具体规则是什么呢?我们来仔细看看库里的
int main()
{
char arr[20] = "abcd";
int t = strncmp(arr, "hjk", 100);
printf("%d", t);
return 0;
}
这个函数其实个人感觉也看不出什么,因为这个没有改变两个字符串的内容,所以就不在调试,直接看结果吧,
对比结果很简单,这个不用我说,一眼就可以看出来,直接看看我们的模拟实现代码吧
int my_strncmp(const char* str, const char* str1,size_t num)
{
assert(str && str1);
while (num)
{
if (*str == *str1)
{
str++;
str1++;
num--;
}
else
{
return *str - *str1;
}
}
return 0;
}
int main()
{
char arr[] = "hfjklsadhfjksdhajkf";
char arr1[20] = "hfjklsadhfjksdhajk";
int ret = my_strncmp(arr, arr1,19);
printf("%d", ret);
return 0;
}
这个实现过程思路和strcmp其实非常类似,唯一不同的就是,strcmp循环出来以后要判断,而strncmp这个函数出来以后就不需要判断,他们的循环条件不一样。我们来看看打印结果
用库里的函数打印的结果是1,而我用的返回结果是*str-*str1,所以就返回的是102,还是根据个人喜好来写,返回1没有错,但是库里函数明显显示的是返回大于0小于0等于0的数,所以只要符合这个规则就可以。
总结:长度受限制和不受限制的字符串函数其实注意事项是差不多的,都是一一对应的,那么,我们现在来说一下为什么受限制的比不受限制的函数相对来说是安全的呢?打个比方,就以strcpy和strncpy来做比较,在使用时,如果我们不小心拷贝的时候,目的地的空间大小不够了,那么此时他还是会拷贝,但是打印的时候才会出现栈被破坏的通知(这个是strcpy),而strncpy这个函数就比较安全了,因为他受长度的限制,所以每次打印的时候,(如果不是故意的话)不会出现站被破坏的情况。其他的几个函数其实和这个是一样的道理,慢慢想就可以理解,这里不再多说。
最后,如果大家感觉又用的话,就点一下赞吧!支持一下!谢谢!