【问题标题】:Unusual behaviour of strings [duplicate]字符串的异常行为[重复]
【发布时间】:2016-09-18 10:42:20
【问题描述】:
#include<stdio.h>
#include<iostream>
#include<cstring>
using namespace std;
int main(void)
{
    char a[10]="Rosewater";
    char b[3];

    int i=0;
    for(i=0;i<5;i++)
    {
        b[i]=a[i]; //1. does not throw an error
    }
    printf("%s\n%s\n",a,b);
}

输出

ewsewater        // value of a also changed

Rosewsewater      // unclear output

【问题讨论】:

  • 你有未定义的行为。
  • 您的代码写到了b 的末尾,从而导致了未定义的行为。未定义的行为可能会导致错误,但并非必须如此。
  • 是的,我明白了.. 但它如何改变字符串 a 的值?那应该保持原样..
  • “未定义的行为”意味着任何事情都可能发生,并且没有定义的结果。这可能是一个段错误。这可能是该程序的明显正确结果。每次程序运行时,结果都可能不同。
  • @SumitKumar 只要本网站(或其他地方)上的某个人说您的程序调用了未定义的行为(“UB”),您就无法推断“应该”发生什么。这就是语言给你 undefined 行为的意义所在,is 没有“应该”。

标签: c++ c string


【解决方案1】:

//1.不会报错

CC++ 中没有边界检查,因为它只是暴露原始内存。

即定义为未定义的行为。 这意味着(简而言之)标准没有指定程序中会发生什么,当指令产生未定义的行为时,任何事情都可能发生。

如果您使用的是C++(与C 不同的语言),我的建议是使用std::vector 类。 Here References.

请注意,当您尝试访问越界索引时,std::vector 会产生未定义的行为。使用 at 方法,在这种情况下会抛出异常。

#include <vector>

int main(int argc, char* argv[]) {
  std::vector<char> a = {'a', 'b', 'c'};
  a.at(5);  // it will throw an exception
  return 0;
}

此外,如果你必须管理字符串,最方便的类是std::string

【讨论】:

  • 但是如果没有完成边界检查,那么我们如何得到分段错误..?
  • @SumitKumar Segfault 在您的程序尝试访问无效地址内存时发生。例如为另一个程序保留的内存空间。在您的情况下,您可能仍在程序空间中访问,并且操作系统不会终止该进程。
【解决方案2】:

在分配的块之外访问内存是一种未定义的行为。

for(i=0;i<5;i++)
{
    b[i]=a[i]; //1. does not throw an error
}

在此循环中,您最终将分配b[3]=a[3]b[4]=a[4]

b[3]b[4] 是未分配的内存块。所以访问它们是一种未定义的行为。

由于未定义的行为,可能会出现不可预知的结果。

按照标准:

可能的未定义行为范围从完全忽略具有不可预测结果的情况,到在翻译或程序执行期间以环境特征的记录方式表现(无论是否发出诊断消息),到终止翻译或执行(发出诊断消息)。

编辑: 对于您关于分段错误的疑问:

分段错误是由访问“不属于您”的内存引起的一种特定类型的错误。但相反的情况并非如此,即您不能说当您访问未分配的内存时您会遇到分段错误记忆。

有些系统在没有内存保护的情况下运行,因此您无法判断一块内存是否真正“属于您”,因此不知道是否会发生分段错误,只能确保未定义的行为。

【讨论】:

  • 那么为什么在某些情况下我们会得到一个段。故障错误。段错误与这种未定义的行为有何不同?
  • @SumitKumar 是否给seg。错误错误与否由实现定义。 C标准没有任何这样的规则。您可能会喜欢阅读此答案stackoverflow.com/a/25636788/4390699
  • @SumitKumar 我已经编辑了我的答案,并试图消除您对段错误的疑虑。
  • 谢谢..这清除了一点..
【解决方案3】:
char b[3]; // [X] [X] [NULL_CHAR] at this point

  int i=0;
  for(i=0;i<5;i++)
  {
     b[i]=a[i]; //1. does not throw an error
  }

所以基本上,当 i=3/4/5 时,您会破坏内存。 这是未定义的行为。 如果您的程序不拥有该内存 - 这将是一个段。过错。 但这只是运气的问题,这个程序的行为是出乎意料的。

【讨论】:

  • 没错,我期待一个段错误错误..为什么它不简单地抛出段错误?!
  • 这条评论 // [X] [X] [X] [NULL_CHAR] at this point 具有误导性或完全错误。
  • @SumitKumar 没必要。发布诊断消息没有强制性规则。
  • @SumitKumar:“为什么它不简单地抛出 seg 错误”因为未定义的行为是......好吧......未定义。
  • b[3] 未初始化,因此它的任何元素都可能带有空字符(NUL'\0'0)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-11
相关资源
最近更新 更多