C++字符串操作中的陷阱

2024-09-06 08:28
文章标签 c++ 操作 字符串 陷阱

本文主要是介绍C++字符串操作中的陷阱,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

休对故人思故国,且将新火试新茶。诗酒趁年华。

                                                                            ——《望江南·超然台作》【宋】苏轼

目录

正文:

首先我们要明白出现问题的原因:

1. 缓冲区溢出

2. 错误的字符串声明方式

3. 缺乏对NULL指针的检查

 解决方案:

下期预告:C++字符串中的string类操作


上期的最后我们抛出了一个新的问题,那就是如果我们发现目标对象的内存已经不足但我们还是将资源对象拼接到目标对象那里,那么在目标内存那里的内存会有什么变化,会对我们的程序有什么危害。现在就让我们看一看:

正文:

我们来看一下代码实例:

#include<iostream>
using namespace std;
#include<string.h>
const int MAX=14;
int main()
{
char s[MAX]={0};
char n[]={"hello"};
chr m[]={"wello"};
char x[]={"only you can do it "}//1
cout<<strcpy(s,n);
//2
cout<<strcpy(s,m,2);
//3
cout<<strcat(s,m);
//4
cout<<strcat(s,x);//新加入的实例int unsigned len=strlen(s);
for(int i=0;i<strlen(s);++i)
{
cout<<s[i]<<endl;
}
return 0;
}

在昨天的代码中我加入了一个新的字符数组,然后将这个字符数组拼接到s数组中,然后输出这个数组。这个时候问题就出现了,我们可以看到在第三步结束时我们的数组s所剩的存储空间还有4个位,但是我们的资源数组(x)的长度远远超过4,所以这个时候就会出现一个问题,那就是数据溢出。我们要知道数据溢出之后就会向后填充溢出的部分,但是这个数组之后的空间存储了其他的数据。这就是说溢出的数据会替换掉下一个位置原本的数据。(比如:我们s数组之后存储的是数组a,那么s数组溢出的数据就会侵占原本a数组中元素的位置,导致a数组的存储内容出现问题。)

这个问题十分的严重,因为一不小心就会导致整个项目出现bug无法运行,尤其可怕的是这种溢出系统是不会报错的,也就是说会在我们不知道的情况下出错。如果是个巨大的项目,那么就是一个十分棘手的bug。


首先我们要明白出现问题的原因:

strcat这类的函数在C语言等编程语言中,用于将两个字符串连接起来,即将源字符串(src)拼接到目标字符串(dest)的末尾。然而,这类函数存在安全缺陷,主要原因包括:

1. 缓冲区溢出
  • 根本原因:strcat函数没有检查目标字符串(dest)的空间是否足够以容纳源字符串(src)。如果dest所指向的缓冲区大小不足以容纳两个字符串连接后的结果,那么strcat会继续在dest的原始内存区域之后写入数据,直到src的末尾。这会导致缓冲区溢出,可能覆盖相邻内存区域的数据,引发程序崩溃或安全漏洞。
  • 危害:缓冲区溢出是许多安全漏洞的根源,攻击者可以利用这一漏洞执行任意代码、提升权限或绕过安全机制。
2. 错误的字符串声明方式
  • 在使用strcat时,如果目标字符串是通过指针指向一个字符串常量(如char *dest = "initial";),则尝试修改这个字符串(即拼接新内容)将导致未定义行为,因为字符串常量通常存储在只读内存区域。
  • 正确的做法是使用字符数组(如char dest[SIZE] = "initial";)来确保有足够的空间进行字符串操作,并且该数组是可修改的。
3. 缺乏对NULL指针的检查
  • 如果strcat的任一参数为NULL,其行为是未定义的。在实际使用中,应该检查指针的有效性,以避免潜在的空指针解引用错误。(主要原因)
 解决方案:

所以C++有了这类函数的升级版,更加的安全:

strnlen_s,strcpy_s,strncpy_s,strcat_s等几个函数

请看优化后的代码:

/*#include<iostream>
using namespace std;
#include<string.h>
#include<cstring>
const int MAX=12;
int main()
{
char s[MAX]={0};
char n[]={"hello"};
char m[]={"wello"};
//cout<<strcpy(s,n);
cout<<strcpy_s(s,MAX,n) << endl;
//cout<<strcpy(s,n,2);
cout<<strcpy_s(s,MAX,n,2);
//cout<<strcat(s,m);
cout<<strcat_s(s,MAX,m);unsigned int len=strlen(s);
for(int i=0;i<len;++i)
{
cout<<s[i]<<endl;
}
return 0;
}
*/#include<iostream>
using namespace std;
#include<string.h>
#include<cstring>const int MAX=12;int main()
{char s[MAX]={0};char n[]={"hello"};char m[]={"wello"};// 使用strncpy来安全地复制字符串strncpy(s, n, MAX);s[MAX-1] = '\0'; // 确保字符串以null终止cout << s << endl;// 使用strncat来安全地连接字符串strncat(s, m, MAX-strlen(s)-1);//求出剩余内存的长度s[MAX-1] = '\0'; // 确保字符串以null终止cout << s << endl;unsigned int len = strlen(s);for(unsigned int i=0; i<len; ++i){cout << s[i] << endl;}return 0;
}

一些第三方库提供了额外的安全函数,这些函数通过检查边界和提供其他保护措施来增强C的安全性。例如,Microsoft的C运行时库(CRT)提供了安全版本的函数,如strcpy_s。(部分编译器可能无法使用)

这里说明一下,代码中其实我列了两种的方式,第一种可能会在编译器中无法通过,所以我又写了第二种方式,这种方式也是可以的,不过就是要自己对结尾加上一个结束符,这就考验编写者的个人细心程度了,所以这种办法也不是很常用,因此在C++中又诞生了一种更简单的,更安全的方法那就是string类里的函数(比如:strlcpy)。

这些代码很简单没什么要特殊注意的,自己记住这些格式就没问题,只需要记住最原始的strcpy之类的函数是没有自动停止的功能,会产生一些隐藏的bug,有这个意识就可以了,即使对此有了完整的技术可以杜绝这种隐患,但是我们还是要保持这种意识,对我们写代码有帮助。

下期我们就来讲一下string类里的相关操作。

🆗到这里,这篇关于:C++字符串操作中的陷阱就说完了,求一个免费的赞,感谢阅读。

下期预告:C++字符串中的string类操作

这篇关于C++字符串操作中的陷阱的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1141504

相关文章

python panda库从基础到高级操作分析

《pythonpanda库从基础到高级操作分析》本文介绍了Pandas库的核心功能,包括处理结构化数据的Series和DataFrame数据结构,数据读取、清洗、分组聚合、合并、时间序列分析及大数据... 目录1. Pandas 概述2. 基本操作:数据读取与查看3. 索引操作:精准定位数据4. Group

MySQL常用字符串函数示例和场景介绍

《MySQL常用字符串函数示例和场景介绍》MySQL提供了丰富的字符串函数帮助我们高效地对字符串进行处理、转换和分析,本文我将全面且深入地介绍MySQL常用的字符串函数,并结合具体示例和场景,帮你熟练... 目录一、字符串函数概述1.1 字符串函数的作用1.2 字符串函数分类二、字符串长度与统计函数2.1

Python操作PDF文档的主流库使用指南

《Python操作PDF文档的主流库使用指南》PDF因其跨平台、格式固定的特性成为文档交换的标准,然而,由于其复杂的内部结构,程序化操作PDF一直是个挑战,本文主要为大家整理了Python操作PD... 目录一、 基础操作1.PyPDF2 (及其继任者 pypdf)2.PyMuPDF / fitz3.Fre

C++11范围for初始化列表auto decltype详解

《C++11范围for初始化列表autodecltype详解》C++11引入auto类型推导、decltype类型推断、统一列表初始化、范围for循环及智能指针,提升代码简洁性、类型安全与资源管理效... 目录C++11新特性1. 自动类型推导auto1.1 基本语法2. decltype3. 列表初始化3

C++11右值引用与Lambda表达式的使用

《C++11右值引用与Lambda表达式的使用》C++11引入右值引用,实现移动语义提升性能,支持资源转移与完美转发;同时引入Lambda表达式,简化匿名函数定义,通过捕获列表和参数列表灵活处理变量... 目录C++11新特性右值引用和移动语义左值 / 右值常见的左值和右值移动语义移动构造函数移动复制运算符

Python对接支付宝支付之使用AliPay实现的详细操作指南

《Python对接支付宝支付之使用AliPay实现的详细操作指南》支付宝没有提供PythonSDK,但是强大的github就有提供python-alipay-sdk,封装里很多复杂操作,使用这个我们就... 目录一、引言二、准备工作2.1 支付宝开放平台入驻与应用创建2.2 密钥生成与配置2.3 安装ali

MySQL 强制使用特定索引的操作

《MySQL强制使用特定索引的操作》MySQL可通过FORCEINDEX、USEINDEX等语法强制查询使用特定索引,但优化器可能不采纳,需结合EXPLAIN分析执行计划,避免性能下降,注意版本差异... 目录1. 使用FORCE INDEX语法2. 使用USE INDEX语法3. 使用IGNORE IND

C# $字符串插值的使用

《C#$字符串插值的使用》本文介绍了C#中的字符串插值功能,详细介绍了使用$符号的实现方式,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧... 目录$ 字符使用方式创建内插字符串包含不同的数据类型控制内插表达式的格式控制内插表达式的对齐方式内插表达式中使用转义序列内插表达式中使用

C++中detach的作用、使用场景及注意事项

《C++中detach的作用、使用场景及注意事项》关于C++中的detach,它主要涉及多线程编程中的线程管理,理解detach的作用、使用场景以及注意事项,对于写出高效、安全的多线程程序至关重要,下... 目录一、什么是join()?它的作用是什么?类比一下:二、join()的作用总结三、join()怎么

详解MySQL中JSON数据类型用法及与传统JSON字符串对比

《详解MySQL中JSON数据类型用法及与传统JSON字符串对比》MySQL从5.7版本开始引入了JSON数据类型,专门用于存储JSON格式的数据,本文将为大家简单介绍一下MySQL中JSON数据类型... 目录前言基本用法jsON数据类型 vs 传统JSON字符串1. 存储方式2. 查询方式对比3. 索引