操纵std :: string

时间:2018-04-09 14:36:17

标签: c++

下面的代码没有给出任何错误/错误/警告(虽然我认为可能会发生一些非法的内存访问)。奇怪的是,使用2种不同方法打印的字符串的大小(strlen和std :: string.size()的出现方式不同。

  

strlen(l_str.c_str() - >给出1500的大小,而,   l_str.size() - >将大小设为0。

#include <string.h>
#include <string>
#include <stdio.h>
#include<iostream>

using namespace std;
void strRet(void* data)
{
        char ar[1500];
        memset(ar,0,1500);
        for(int i=0;i<1500;i++)
                ar[i]='a';
        memset(data,0,1500); // This might not be correct but it works fine
        memcpy(data,ar,1500);
}
int main()
{
        std::string l_str;
        cout<<endl<<"size before: "<<l_str.length();
        int var=10;
        strRet((void *)l_str.c_str());
        printf("Str after call: %s\n",l_str.c_str());
        cout<<endl<<"size after(using strlen): "<<strlen(l_str.c_str());
cout<<endl<<"Size after(using size function): "<<l_str.size();
        printf("var value after call: %d\n",var);
        return 0;
}

如果我做了一些我不应该做的事情,请提出建议!

另外,当我memset(data,0,1500);时,我想知道哪些内存字节被设置为0?我的意思是,如果假设我的字符串变量的起始地址是100,那么memset命令是否将内存范围[100,1600]设置为0?或者是否设置了其他一些内存范围?

1 个答案:

答案 0 :(得分:4)

memset(data,0,1500); // This might not be correct but it works fine

这是不正确的,它并没有“正常工作”。这是未定义的行为,你犯了一个常见的错误,即如果它编译,你的计算机没有立即着火,一切都很好。

实际上并非如此。

  

我做过一些我不应该做的事情!

是的,你有。你拿了一个指向std::string的指针,这是一个非平凡的对象,它有自己的状态和行为,要求它输入一些内存它控制的地址,并将其转换为{{1} }。

没有理由这样做,你应该非常很少在C ++代码中看到void*,并且看到任何类型的C风格转换都非常令人担忧。

不要将void*指针放入具有void*等状态和行为的对象,直到您了解自己在做什么以及为什么这是错误的。然后,当那一天到来时,你仍然不会这样做,因为你会更清楚。

我们可以在一些细节上看第一个问题,如果它有帮助:

std::string
  • (void *)l_str.c_str() 返回什么?指向c_str()
  • 拥有的某些内存的指针
  • 这个记忆在哪里?不知道,这是l_str的业务。如果此标准库实现使用小字符串优化,则它可能 in l_str对象。如果没有,可以动态分配。
  • 此位置分配了多少内存?不知道,这是l_str的业务。我们可以肯定地说,至少有一个合法可寻址的char(l_str)并且使用地址l_str.c_str()[0] == '\0'是合法的(但仅作为一个过去的指针) ,所以你不能取消引用它)

所以,声明

l_str.c_str()+1

strRet((void *)l_str.c_str()); 指针传递给包含一个或多个可寻址字符的位置,其中第一个为零。那是我们可以说的一切

现在让我们再看一下有问题的一行

strRet

为什么我们期望在这个位置有1500个字符?如果您将memset(data,0,1500); // This might not be correct but it works fine 记录为需要至少1500个已分配字符的缓冲区,那么当您知道 strRet时,实际传递l_str.c_str()是否合理默认构造为字符串?这不像您要求l_str为您分配该存储空间。

你可以通过调用

l_str有机会分配你想要写的内存来开始这项工作。
l_str

在致电l_str.reserve(1500); 之前。这仍然不会通知strRet您用l_str填充它,因为您通过更改其背后的原始内存来做到这一点。

如果您希望此功能正常运行,则可以用

替换整个'a'
strRet

或者,如果要使用

正确更改现有字符串
std::string l_str(1500, 'a');