【问题标题】:C++ strcat creating infinite loopC ++ strcat创建无限循环
【发布时间】:2016-11-16 00:13:03
【问题描述】:

我正在尝试创建一个数组,并且数组中的每个对象都应该具有名称 Model(i),其中是索引,我这样做是为了让它们的名称按 Model5、Model4 的降序索引...我正在尝试使用 char[] 执行此操作,但由于某种原因,在我的代码中,在 for 循环中使用 strcat 使我陷入无限循环,如果有人可以提供帮助,第二点是以我可以连接的方式转换索引命名并给构造函数。

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

using namespace std;

class CARRO {
    public:
        CARRO() {};
        CARRO(char *modelo, unsigned ano);
        char* getModelo();
        unsigned getAno();
    private:
        char modelo[100];
        unsigned ano;
};

void swap(int *p, int *q);
int partition(int *v, int start, int end);
int randomizedPartition(int *v, int start, int end);
void qsHelper(int *v, int start, int end);
void quickSort(int *v, int len);
void printList(CARRO *carros, unsigned len);

int main(int argc, char const *argv[]) {

    CARRO carros[5];
    unsigned len = sizeof(carros)/sizeof(CARRO);

    for (int i = 0; i < len; ++i) {
        char modelo[] = "Modelo";
        char id[] = "I";
        strcat(modelo, id);
        unsigned ano = 1000 * (i+1);
        carros[i] = CARRO(modelo, ano);
        cout << carros[i].getModelo() << endl;
    }

    //printList(carros, len);

    return 0;
}

CARRO::CARRO(char *modelo, unsigned ano) {
    strcpy(this->modelo, modelo);
    this->ano = ano;
}

如果我删除该行:

strcat(modelo, id);

循环工作正常。我只是不明白为什么 strcat 会以某种方式生成无限循环。输出是这样的:(使用 strcat 行)

ModeloI
ModeloI
ModeloI
ModeloI
ModeloI
ModeloI
ModeloI
ModeloI
ModeloI
ModeloI
^CModeloI

【问题讨论】:

  • 如果你使用 C++,你应该使用 std::string 和相关的方法而不是 C 的 strcat 和字符数组
  • modelo 仅创建大到足以容纳您初始化它的单词。如果您使用 std::strcat 使其内容更长,则您在数组边界之外写入会导致未定义的行为。
  • 您在char modelo[] = "literal" 上没有收到警告吗?我认为您使用代码输入了任何可能发生的区域。检查这个:stackoverflow.com/questions/8356223/…
  • @GovindParmar 我想我会结束这样做,但是有什么可以解决这个错误的吗?或者解释一下为什么 strcat 会导致这种情况?就像循环哨兵定义明确并且没有改变循环内 i 的值。我知道为什么会这样:(

标签: c++ loops infinite strcat


【解决方案1】:

循环工作正常。我只是不明白为什么 strcat 会以某种方式生成无限循环。输出是这样的:(使用 strcat 行)

循环工作正常!你在浪费内存。让我们制作一些框来表示堆栈,因为您的程序可能会看到 (假设循环刚刚转到 1):

+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| char modelo[7]                          | int i                 | unsigned len          |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| 'M' | 'o' | 'd' | 'e' | 'l' | 'o' | 0   | 1   | 0   | 0   | 0   | 5   | 0   | 0   | 0   |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+

所以当你这样做时:

strcat( modelo, id );

最终会导致缓冲区溢出一个字节。在我的特定示例中,这会覆盖变量 i 的第一个字节,从而导致您的循环无限期地继续:

+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| char modelo[7]                          | int i                 |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| 'M' | 'o' | 'd' | 'e' | 'l' | 'o' | 'I' | 0   | 0   | 0   | 0   |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
                                           ^^^^^
                                           Nul-terminator written

当然,我这样布置你的堆栈纯粹是作为一个例子。您的编译器可能不会像这样将堆栈保持在一起。 可能在你的数组之后有额外的填充,它可能只是碰巧“工作”。变量i 可能 保存在寄存器中而不是内存中,或者编译器可能 已完全展开循环。您的架构可能是大端(而不是我的示例中的小端)。

关键是,结果行为是完全未定义的。即使您在机器上获得一致的结果,我们也无法查看此代码并说出会发生什么。

因此,要解决此问题,您只需将modelo 设置为足够大以存储包含终止符的字符串"ModeloI",这意味着使其足够大以存储 8 个字节而不是 7 个:

char modelo[8] = "Modelo";

然后,您将定义行为,无论堆栈是如下布局还是其他方式:

+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| char modelo[8]                                | int i                 |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| 'M' | 'o' | 'd' | 'e' | 'l' | 'o' | 'I' | 0   | 1   | 0   | 0   | 0   |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+

【讨论】:

  • 非常感谢@paddy 的解释,我决定使用std::string,所以问题现在已经解决了!但是非常感谢,现在我会在使用 char[] 时意识到这一点。
猜你喜欢
  • 1970-01-01
  • 2021-02-20
  • 2021-08-11
  • 1970-01-01
  • 1970-01-01
  • 2017-04-07
  • 2015-01-24
  • 2016-03-21
  • 2020-02-24
相关资源
最近更新 更多