为什么我的范围基于循环崩溃我的C ++程序?

时间:2013-01-20 21:07:13

标签: c++ for-loop c++11 clang

我正在尝试使用基于for循环的新C ++ 11范围。这是我的计划:

#include <iostream>
#include <string>
#include <sstream>
#include <fstream>

using namespace std;

ofstream logger("log.txt");
void log(string message)
{
    logger << message << std::endl;
    logger.flush();
}

int main( int argc, char* args[] )
{
    log("hello world");
    cout << "hello world\n";

    log("declare sort me");
    int sortMe[10];

    log("loop sortMe");
    for(int i : sortMe) {
        log("in loop " + i);
        sortMe[i] = i + 1;
    }
}

我使用clang ++进行编译。它汇编了警告:

clang++ -o mycpp mycpp.cpp
mycpp.cpp:24:12: warning: range-based for loop is a C++11 extension
      [-Wc++11-extensions]
        for(int i : sortMe) {
                  ^
1 warning generated.

当它运行时,我得到这个输出:

hello world
Segmentation fault (core dumped)

根据log.txt文件,程序进入for循环,但它永远不会进入for循环。我错过了什么?

5 个答案:

答案 0 :(得分:10)

这个循环:

for(int i : sortMe) {
    log("in loop " + i);
    sortMe[i] = i + 1;
}

循环并返回sortMe数组中存储的,而不是sortMe数组的 indices 。结果,查找sortMe[i]将跳转到数组的完全随机索引(可能是方式,超出范围),导致段错误。

如果要将每个元素设置为等于其位置,只需使用普通for循环:

for (int i = 0; i < 10; i++) {
    sortMe[i] = i + 1;
}

另外,正如@hmjd所指出的,对log的调用将无法正常工作,因为您正在对字符串进行指针运算,而不是进行字符串连接。

希望这有帮助!

答案 1 :(得分:5)

您正在使用基于范围的for循环,您应该使用标准for循环。循环中的int i 不是当前元素的索引,而是该元素的值。也就是说,如果您的数组包含{1, 3, 3, 7},则每次迭代时i的值为1,然后为3,然后为3,然后为{{1} }}。由于您的数组未初始化,因此您不知道7的值是什么,并且您将获得未定义的行为。

如果您想在for循环中使用索引,请使用标准for循环:

i

请注意,要与for(int i = 0; i < 10; i++) { log("in loop " + std::to_string(i)); sortMe[i] = i + 1; } 进行字符串连接,您的一个操作数需要为+。否则,您将std::string添加到指向i中第一个字符的指针。

答案 2 :(得分:3)

for循环中对log()的调用不正确。参数是指针运算的结果,未知的int值用作字符串文字基址的偏移量。

使用std :: to_string()将int转换为std :: string。

提到std:iota,可用于将范围的元素设置为基于初始值的增加值:

std::iota(std::begin(sortMe), std::end(sortMe), 1);

答案 3 :(得分:1)

我认为您希望基于范围的循环可以做与其不同的操作......

如果你写for (int var: array) { log(var); }那么代码将被执行的次数与数组中的元素一样多。每次var都等于数组的一个元素。请注意,我直接使用var作为数组元素,而不是array[var]

例如,如果你有int[3] array = { 42, 69, 1337 };,循环的先例将记录42,69和1336。

因此,如果我只做int[3] array;,循环的先例将循环存储数组的内存中的三个随机整数...如果不是直接使用var我是使用array[var]它很可能会崩溃,因为var不是array的有效索引。


<强>解决方案:

不要对数组元素和索引之间的区别感到困惑......

  • 如果您想直接操作数组的元素:

    for(int element : sortMe) {
        /* Do something with the element */
    }
    
  • 如果要使用索引,请不要使用基于范围的循环:

    for(int index = 0; index < 10; ++index) {
        /* Do something with the index */
    }
    

答案 4 :(得分:0)

请不要向上或向下投票。我只是添加了一个我通常会添加的评论来帮助问题的人,但是因为你无法格式化....

你可以按照你想要的方式做新的方式,但这是一个相当无意义的练习,最好用常规的循环来完成。范围循环返回值,而不是引用。至少在你使用它的方式。

 int count = 0;
 // Use a reference so we can update sortMe
 for (int& i : sortMe) {
    i = ++count;
 }

看着它,它比正常的循环更紧凑,奇怪的是我更喜欢它。 ;)