修改字符串的长度和内容

Modifying the length and contents of the string?

本文关键字:字符串 修改      更新时间:2023-10-16

要改变函数中字符串的内容,使其反映在主函数中,我们需要接受该字符串作为引用,如下所示。

用函数

修改std::string的内容

但是在上面的代码中,我们也改变了字符串的大小(i。E,超过它所能容纳的),那么为什么程序没有崩溃呢?

程序将十进制转换为二进制,请注意,代码不完整,我只是测试代码的第一部分。

void dectobin(string & bin, int n)
{
  int i=0;
  while(n!=0)
  {
     
     bin[i++]= (n % 2) + '0';
     n = n / 2;
   }
  cout << i << endl;
  cout << bin.size() << endl;
  cout << bin << endl;
}
int main()
{
   string s = "1";
   dectobin(s,55);
   cout << s << endl;
   return 0;
}

O/p: 6 11 1,程序在代码块中崩溃。虽然上面的代码在链接中工作得很好。

它只输出正确的结果,当我用6个字符初始化main中的字符串(i。E,数字从十进制转换为二进制后的长度)。

http://www.cplusplus.com/reference/string/string/capacity/

请注意,此容量不假设字符串的长度有限制。当此容量耗尽并且需要更多容量时,对象会自动对其进行扩展(重新分配其存储空间)。字符串长度的理论限制由成员max_size

给出。

如果字符串自动调整大小,那么为什么我们需要resize函数,然后为什么我的十进制到二进制代码不工作?

你的前提是错误的。你在想1)如果我访问超出边界的字符串,那么我的程序将崩溃,2)我的程序不会崩溃,因此我不能访问超出边界的字符串,3)因此我显然超出边界的字符串访问实际上必须调整字符串的大小。

1)不正确。越界访问字符串会导致未定义的行为。这就是字面意思。你的程序可能会崩溃,但也可能不会,它的行为是未定义的。

事实上,访问字符串永远不会改变它的大小,这就是为什么我们有resize函数(和push_back等)。

像你这样的问题我们一周一定会收到好几次。未定义行为显然是一个让新手感到惊讶的概念。

查看std::string的链接:

      char& operator[] (size_t pos); 
const char& operator[] (size_t pos) const;

如果pos不大于字符串长度,则该函数永远不会抛出异常(无抛出保证)。否则,它会导致未定义的行为。

while循环中,您正在访问索引大于bin.size()bin字符串

你没有改变字符串的大小。如果你传递给函数的字符串长度是1,并且你在索引大于0的地方访问它,即在bin[1], bin[2],你没有修改字符串,而是在字符串之后的其他内存位置-可能有其他东西存储在那里。以这种方式破坏内存并不一定直接导致崩溃或异常。一旦你在以后的程序中访问了这些内存位置,它就会返回。

接受对字符串的引用使得从调用代码更改被调用代码中的字符串实例成为可能:

void access(std::string & str) {
  // str is the same instance as the function
  // is called with.
  // without the reference, a copy would be made,
  // then there would be two distinct instances
}
// ...
std::string input = "test";
access(input);
// ...

因此,在引用上调用的任何函数或操作符都有效地在被引用的实例上调用。

当,类似于你的链接问题,代码

str = " new contents";

access函数体中,然后调用input实例的operator=

This(复制赋值)操作符丢弃字符串先前的内容,然后将其实参的字符复制到新分配的存储中,新分配的存储所需的长度之前已确定。

另一方面,当你有像 这样的代码时
str[1] = 'a';

access函数内,然后在input实例上调用operator[]。此操作符仅提供对字符串的底层存储的访问,而不进行任何大小调整。

所以你的问题与引用无关,而是滥用索引operator[]:

使用不小于string对象size/length的实参调用该操作符将导致未定义行为。

要解决这个问题,可以在使用索引操作符之前手动调整字符串的大小。

作为旁注:在我看来,你应该试着用更实用的方式来写你的函数:

std::string toOct(std::string const &);

也就是说,不修改绿洲字符串,而是创建一个新的。

字符串的边界受当前内容的限制。这就是为什么当你用6个字符初始化字符串时,你将保持在将55转换为二进制和程序运行无错误的范围内。字符串的自动扩展特性可以使用std:: string::操作符+ =在当前字符串的末尾附加字符。修改后的代码片段如下所示:

void dectobin(string & bin, int n){
//...
bin += (n % 2) + '0';
//...
}

另外,你不需要在main()中初始化原始字符串,你的程序现在可以运行任意小数。

int main(){
//...
string s;
dectobin(s,55);
//...
}