0

如果我可能没有正确表达问题,我很抱歉,但在以下代码中:

int main() {
char* a=new char[5];
a="2222";
a[7]='f';     //Error thrown here
cout<<a;
}

如果我们试图在程序中访问 a[7],我们会得到一个错误,因为我们没有被分配 a[7]。

但是如果我在课堂上做同样的事情:

class str
{
public:
    char* a;
    str(char *s) {
        a=new char[5];
        strcpy(a,s);
    }
};
int main()
{
    str s("ssss");
    s.a[4]='f';s.a[5]='f';s.a[6]='f';s.a[7]='f';
    cout<<s.a<<endl;
    return 0;
}

该代码有效,打印字符“abcdfff”。当我们只将 char[5] 分配给我们在第一个程序中无法这样做的时候,我们如何能够访问代码中的 a[7] 等?

4

4 回答 4

3

在您的第一种情况下,您有一个错误:

int main() 
{
    char* a=new char[5];   // declare a dynamic char array of size 5
    a="2222"; // assign the pointer to a string literal "2222" - MEMORY LEAK HERE
    a[7]='f';     // accessing array out of bounds!
    // ...
}

您正在创建内存泄漏,然后询问为什么未定义的行为未定义。

您的第二个示例再次询问为什么未定义的行为未定义。

于 2013-09-19T17:50:15.067 回答
1
int main() {
  char* a=new char[5];
  a="2222";
  a[7]='f';     //Error thrown here
  cout<<a;
}

如果我们试图在程序中访问 a[7],我们会得到一个错误,因为我们没有被分配 a[7]。

不,您在访问受写保护的内存时会出现内存错误,因为a它指向 的只写内存"2222",并且偶然在该字符串末尾的两个字节也受到写保护。如果您使用与strcpy在 中使用的相同class str,则内存访问将在分配的内存之后覆盖一些“随机”数据,这很可能不会以同样的方式失败。

访问您分配的内存之外的内存确实是无效的(未定义的行为)。生成并在其上运行代码的编译器、C 和 C++ 运行时库和操作系统不能保证检测到所有这些事情(因为检查访问内存的每个操作可能非常耗时)。但保证访问已分配内存之外的内存是“错误的”——它只是并不总是被检测到。

于 2013-09-19T17:59:14.977 回答
1

正如其他人所说,这是未定义的行为。当您写入内存超出为指针分配的内存范围时,可能会发生几件事

  1. 您覆盖已分配但未使用且迄今为止不重要的位置
  2. 你覆盖了一个存储对你的程序很重要的东西的内存位置,这将导致错误,因为你已经破坏了你自己的内存
  3. 您覆盖了一个不允许访问的内存位置(超出程序内存空间的东西)并且操作系统吓坏了,导致诸如“AccessViolation”之类的错误

对于您的具体示例,分配内存的位置取决于变量的定义方式以及必须为程序运行分配的其他内存。这可能会影响出现一个或另一个错误或根本没有出现错误的概率。但是,无论您是否看到错误,您都不应该访问分配的内存空间之外的内存位置,因为就像其他人所说的那样,它是未定义的,并且您将获得与错误混合的非确定性行为。

于 2013-09-19T17:55:37.053 回答
1

正如其他答案中提到的,访问数组末尾之后的内存是未定义的行为,即您不知道会发生什么。如果幸运的话,程序会崩溃;如果没有,程序会继续执行,就好像没有出错一样。

出于性能原因,C 和 C++ 不对(简单)数组执行边界检查。

语法a[7]只是意味着转到内存位置X + sizeof(a[0]),开始存储X的地址在哪里,然后读/写。a如果您尝试在保留的内存中读/写,一切都很好;如果在外面,没人知道会发生什么(请参阅@reblace 的答案)。

于 2013-09-19T18:01:54.440 回答