2

我正在尝试使用基于 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 循环。我错过了什么?

4

5 回答 5

10

这个循环:

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

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

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

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

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

希望这可以帮助!

于 2013-01-20T21:11:48.387 回答
5

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

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

for(int i = 0; i < 10; i++) {
    log("in loop " + std::to_string(i));
    sortMe[i] = i + 1;
}

请注意,要与 进行字符串连接+,您的操作数之一需要是std::string. 否则,您将添加i到指向第一个字符的指针"in loop "

于 2013-01-20T21:11:55.003 回答
3

for 循环中对 log() 的调用不正确。参数是指针算术的结果,一个未知的 int 值被用作相对于字符串字面量基地址的偏移量。

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

仅提及std:iota,它可用于将范围的元素设置为基于初始值的递增值:

std::iota(std::begin(sortMe), std::end(sortMe), 1);
于 2013-01-20T21:11:23.483 回答
1

我认为您希望基于范围的循环做一些不同于它所做的事情......

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

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

因此,如果我只是这样做int[3] array;,则前面的 for 循环将循环三个已经在存储数组的内存中的随机整数......如果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 */
    }
    
于 2013-01-20T21:21:42.947 回答
0

请不要对此投赞成票或反对票。我只是添加一个我通常会作为评论添加的点,以帮助该人解决问题,但由于您无法格式化....

你可以用新的方式做你想做的事,但这是一个相当没有意义的练习,最好使用常规的 for 循环来完成。range 循环返回值,而不是引用。至少在你使用它的方式上。

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

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

于 2013-01-20T21:23:02.390 回答