在掌握了strcpy函数和strcpy_s函数之后,我们不可避免地会谈到strncpy函数和strncpy_s函数,其实这四个函数的功能几乎一致,就是对两个字符串数组进行复制和赋值,但是具体实现有一点点区别。

首先来说一下strncpy函数。该函数依然还是存在于标准名称空间std内,出现的目的很简单,对于strcpy函数,只能将两个字符串进行完整的复制和赋值,这里就会产生一个实际应用时的问题,如果我们只需要复制某个字符串的前几个字符呢?

其实对于这个问题,我们首先可能会想到使用strcpy_s函数,因为该函数有一个长度,我们在安全函数的基础上将长度表示成我们希望复制的长度,但是实际运行时这样写会出现问题,举例如下:

// strncpy_s.cpp
//#include "stdafx.h"
#include <iostream>
#include <cstring>int main()
{using namespace std;char str1[100];char str2[5];cout << "Please enter your favorite lines (Warning: No longer than 100!):\n";cin.getline(str1, 100);strcpy_s(str2, 5, str1);cout << "str1 is " << endl << str1 << endl;cout << "while str2 is " << endl << str2 << endl;system("pause");return 0;
}

对于以上代码,运行结果如下图所示:

由运行结果可知,Buffer is too small,即告诉我们安全函数之所以安全,就是不可以这样操作,不可以把一个长度超过x的字符串数组复制并赋值给长度为x的字符串数组。

于是由此,strncpy函数应运而生。

由于我使用的IDE是Visual Studio 2017,所以只要使用strncpy函数就会报错并提示使用安全版本,所以这里对于基础版本的strncpy函数只做理论介绍。

strncpy函数的原型如下所示:

char * strncpy(char * str2, char * str1, int size);

功能就是复制str1中的内容,赋进str2中,复制的长度由size的数值决定,size的类型不一定是Int,但我们一般来说遇到的长度都是整数,所以这里用int比较简单。

比如说以下语句:

char str1[5] = "abcd";
char str2[10] = "leonardo";
strncpy(str2, str1, 3);

因为IDE不支持基础版本函数,所以我没法看运行结果,就文字描述一下。

以上代码运行之后,strncpy函数会将str1的前3个字符的内容复制,赋到str2里,于是str2就变成了‘a’'b'‘c’。

那么对于strncpy_s函数,原型如下所示:

strncpy_s(char * str2, int size2, char * str1, int size1);

这里多了一个长度,就是被复制的str2的长度,我们可以用sizeof(str2)来表示这个长度。

那么改成使用strncpy_s函数之后,上面的代码就可以正确运行了。

// strncpy_s.cpp
//#include "stdafx.h"
#include <iostream>
#include <cstring>int main()
{using namespace std;char str1[5] = "abcd";char str2[10] = "leonardo";cout << "str1 is " << endl << str1 << endl;cout << "str2 is " << endl << str2 << endl;strncpy_s(str2, sizeof(str2), str1, 3);cout << "after the copy str2 is " << endl << str2 << endl;system("pause");return 0;
}

运行结果如下图所示:

于是回到我们最早那个代码,稍作修改使用strncpy_s函数,修改后代码如下:

// strncpy_s.cpp
//#include "stdafx.h"
#include <iostream>
#include <cstring>int main()
{using namespace std;char str1[5] = "abcd";char str2[10] = "leonardo";cout << "str1 is " << endl << str1 << endl;cout << "str2 is " << endl << str2 << endl;strncpy_s(str2, sizeof(str2), str1, 3);cout << "after the copy str2 is " << endl << str2 << endl;char str3[100];char str4[10];cout << "Please enter your favorite lines (Warning: No longer than 100!):\n";cin.getline(str3, 100);strncpy_s(str4, sizeof(str4), str3, 10);cout << "str3 is " << endl << str3 << endl;cout << "while str4 is " << endl << str4 << endl;system("pause");return 0;
}

对于str3,它本身的长度是100,用户输入可以输入小于100的任意长度的字符,但是str4没有这么长,它的长度只有10,所以只能把str3的前10个字符内容复制给str3。

但是上面这样写还是有点问题,那就是字符串数组的最后一位一定是‘\0',如果直接复制10位,无法赋进str4,因为这样就把它最后一位的'\0'给覆盖了,就会报错,所以我们修改上面代码的strncpy_s()函数那里,改为

strncpy_s(str4, sizeof(str4), str3, 9);

这样就正确了。

运行结果如下图所示:

于是就完成了我们之前所说的,希望只复制某个字符串数组的一部分给另一个字符串数组的功能了。

其实这个功能还可以延伸,假如说,我们希望复制的字段并不是原字符串最开始的字符怎么办呢,其实也很简单,只需要在strncpy_s函数的第三个参数处进行操作就可以了。

比如说我们希望从第2个字符开始复制,那么第3个参数就由"str3"改写为"str3+1"即可。因为str3是数组,数组名直接使用而不带标号,即是表示地址,所以“str3+1”即是表示str3[1]的地址了,同理"str3+5"即是表示str[5]的地址。

于是我们把上述程序的第23行,即strncpy_s()函数赋值那一句改成如下所示:

strncpy_s(str4, sizeof(str4), str3 + 1, 9);

运行结果如下图:

从图中可以看出,确实是从第2个字符开始复制的。

那么接下来我们就要考虑,如果希望复制的不是连续的字符,而是分散的,比如说str3[2],str3[5],str3[8]和str3[9]这种呢?

这种情况就需要多个strncpy_s语句了,因为每一句只能进行一次复制和赋值,多次才能完成上述任务。

此时我们就需要去操作第1个参数了,即str4,因为str4也是一个数组名表示地址,所以我们这样分散复制时,后面几次复制就需要从str4的str4[2]开始赋值了。

我们来看一下完整代码:

// strncpy_s.cpp
//#include "stdafx.h"
#include <iostream>
#include <cstring>int main()
{using namespace std;char str1[5] = "abcd";char str2[10] = "leonardo";cout << "str1 is " << endl << str1 << endl;cout << "str2 is " << endl << str2 << endl;strncpy_s(str2, sizeof(str2), str1, 3);cout << "after the copy str2 is " << endl << str2 << endl;cout << endl;char str3[100];char str4[10];cout << "Please enter your favorite lines (Warning: No longer than 100!):\n";cin.getline(str3, 100);cout << endl;strncpy_s(str4, sizeof(str4), str3 + 2, 1);strncpy_s(str4 + 1, sizeof(str4) - 1, str3 + 5, 1);strncpy_s(str4 + 2, sizeof(str4) - 2, str3 + 8, 2);cout << "str3 is " << endl << str3 << endl;cout << "while str4 is " << endl << str4 << endl;system("pause");return 0;
}

上述代码的第25,26,27三行都是在进行strncpy_s函数的复制,可以看到我们分了3次复制,因为str3[2],str3[5]都只能单独复制,因为不连续,而str3[8]和str3[9]可以联合复制,因为连续。

上述代码运行结果如下图所示:

从图中可以看到,str3[2]是‘ ’,str3[5]是'm',str3[8]是'i',str3[9]是's'。

所以这样我们就完成了分散复制的功能了。

目前我掌握的有关strncpy函数和strncpy_s函数的使用及注意事项就是这样,以后继续学习遇到新的知识了会持续补充。

C++中strncpy函数和strncpy_s函数的使用及注意事项相关推荐

  1. 【C语言】strncpy函数和strncpy_s函数的不同!关于末尾追加\0

    今天在微软家的strncpy_s函数上栽了跟头,记录一下 char *strncpy(char *strDest, const char *strSource, size_t count ); err ...

  2. C语言中字符串相关的拷贝函数

    C语言下字符串拷贝函数汇总对比 1.1.strcpy 函数原型char *strcpy(char *dest, const char *src) 需要注意的是如果目标数组 dest 不够大,而源字符串 ...

  3. strlen函数,strcat函数,strcpy函数,strncpy函数,strcmp函数

    strcpy函数: char *strcpy(char *Dest , const char *Src) { assert((Dest != NULL) && (Src != NULL ...

  4. C语言中的字符串与字符串函数

    一.gets()函数 gets()函数在其函数声明中声明括号中的类型为char *.但当我尝试下列操作时却给出了警告:p没有使用. #include<stdio.h> int main() ...

  5. C语言中的字符函数和字符串函数

    目录 前言 1.常用函数介绍 1.1 strlen 1.2 stycpy 1.3 strcat 1.4 strcmp 1.5 strncpy 1.6 strncat 1.7 strncmp 1.8 s ...

  6. 字符函数和字符串函数详解(二)strncpy strncat strncmp strstr strtok(及其模拟实现)

     系列文章目录 字符函数和字符串函数详解(一)strlen strcpy strcat strcmp 字符函数和字符串函数详解(二)strncpy strncat strncmp strstr str ...

  7. C++深度解析 类中的函数重载 -- 全局函数,普通成员函数,静态成员函数(28)

    C++深度解析 类中的函数重载 -- 全局函数,普通成员函数,静态成员函数(28) 函数重载的回顾 函数重载的本质为相互独立的不同函数 C++中通过函数名和函数参数确定函数调用 无法直接通过函数名得到 ...

  8. 如何在sqlite3连接中创建并调用自定义函数

    #!/user/bin/env python # @Time :2018/6/8 14:44 # @Author :PGIDYSQ #@File :CreateFunTest.py '''如何在sql ...

  9. mysql 字段加减_MySQL中你必须了解的函数

    在学习MySQL的时候你会发现,它有非常多的函数,在学习的时候没有侧重.小编刚开始学习的时候也会有这个感觉.不过,经过一段时间的学习之后,小编发现尽管函数有很多,但是常用的却只有那几个.今天小编就把常 ...

  10. PCL common中常见的基础功能函数

    这里将分享我使用PCL库的遇到的一些坑,以及总结的技巧,当然也需要各位能够多多分享,将公众号的文章或者知识星球的文章转发到朋友圈. pcl_common中主要是包含了PCL库常用的公共数据结构和方法, ...

最新文章

  1. ubuntud——系统备份和恢复
  2. 2018.11月Android优质开源项目
  3. 请重新认识你作为程序员的价值
  4. Quartus11中新建工程
  5. Python 技术篇-用flask服务实现mac本地文件上传至windows服务器指定文件夹下实例演示
  6. bzoj1833: [ZJOI2010]count 数字计数USACO37 Cow Queueing 数数的梦(数位DP)
  7. mybatis 插入数据时返回主键
  8. 【ElasticSearch】Es 源码之 LicenseService 源码解读
  9. linux信号(一)--unix环境高级编程读书笔记
  10. 接口测试第二课(Fiddler实现APP抓包)
  11. 第二步_安装samba服务器
  12. 2008年5月Windows Mobile Webcast预告
  13. [转载]github在线更改mysql表结构工具gh-ost
  14. java kettle jar包_Kettle中调用用户自定义的jar包
  15. golang中的错误fatal error: concurrent map writes
  16. 计算机网络语音传输杂音回音,QQ语音时,怎么消除麦克风回音、噪音、杂音
  17. Redis高级特性RDB、AOF、事务、Stream、Pipeline和Lua脚本
  18. python xlrd获取excel行数_Python 使用xlrd库读取excel,获取最大行和最大列等
  19. 地铁三号线 - 为什么哭的时候总是叫我带娃?
  20. IPTV系统中EPG模块的设计与实现

热门文章

  1. linux卸载wine qq,ubuntu安装wineQQ
  2. Symantec BE 安装及备份oracle 完整版
  3. SogouLabDic搜狗词库
  4. 条件语句与循环语句:将数字一二三四五六七八九十转化成汉字大写的壹, 贰,叁,肆,伍,陆,柒,捌,玖,拾
  5. 西门子plc电源开关如何选型
  6. 增霸卡出现问题 保护解不开
  7. 漫游项目服务器,漫游Radius服务器的设计与实现
  8. 啦啦外卖php版本,微信外卖源码,微信啦啦外卖plus跑腿版 v5.0.7开源版
  9. 没钱充会员 百度网盘下载限速怎么办?这些招可以突破百度网盘非会员限速限制
  10. 嵌入式和单片机开发模式的区别