这是我在词法分析器的代码中用作辅助函数的一个小 lambda 函数:
auto buildnumber = [&line, &i] () -> Token* {
Token* new_number = new Token(nullptr, number, line);
char** after_number = nullptr;
double* value = new double(std::strtod(i, after_number));
printf("Value got: %f\n", *value);
printf("Comparing it to 0\n");
if (*value == 0.0) {
printf("value was 0, comparing position to after number\n");
if (i == *after_number) {
printf("No number detected\n");
delete value;
delete new_number;
return nullptr;
}
}
printf("Value was different from 0, storing it in Token\n");
new_number->value = (void*) value;
printf("Advancing position\n");
i = *after_number;
printf("Returning\n");
return new_number;
};
这里有一些背景知识:Token
是一个类,它有一个类型为 void
的属性 value
,一个属性 line
类型 int
,以及自定义枚举 token_type
的属性 type
。在第一行中,我初始化一个新的,将一个空指针传递给它的构造函数(因为我们仍然必须创建它),枚举 token_type
的值(number
因为这个标记属于那种类型),以及我们在 lambda 中捕获的当前行。
i
是一个类型为 const char*
的指针,它指向我们正在检查的当前字符。当我们调用此 lambda 函数时,它保证指向一个可打印字符。
printf
用于调试;
所以我想做的是:创建一个内部类型为 number
的新 Token
;询问 strtod
我们是否可以从当前位置构建一个数字;然后检查 strtod
是否返回了一个非零值,在这种情况下,我们将该值存储在新的 Token
中,将我们指向的字符的位置提前到数字后面的字符,返回Token
。
如果 strtod
返回的是零值,我们必须仔细检查该零值是因为找到了实际的 0,还是无法构建数字。因此,我们检查指向数字后字符的指针是否指向与当前位置相同的字符:如果为真,则意味着 strtok
没有推进该指针,这意味着根本没有数字找到了(并且我们删除了分配的值并返回一个空指针来表示)。否则,这意味着找到了一个 0,因此我们将其存储、前进并返回。
问题是,当我尝试引用 after_number
时,我确实 每次 都会收到段错误:也就是说,如果我调用 buildnumber
时i
指向像 "111"
这样的字符串,在它打印 "Advancing position"
后我得到了一个段错误。如果我在 i
指向像 "+0.0"
或 "abc()"
这样的字符串时调用它,我会在它之后得到一个段错误打印 “Value was 0, comparing position to after number”
。
这是为什么呢? after_number
指向的指针会发生什么变化?我做错了什么?
最佳答案
您已将 after_number
定义为指向字符指针的指针,然后当它实际上没有指向任何有用的东西时直接使用它。
问题在于,您基本上是在告诉 strtod
不要实际存储 结束指针(因为您已经提供了 nullptr
作为存储它的地址),然后你继续尝试取消引用它——它仍然是 nullptr
,因此你会得到未定义的行为。
正确的做法如下:
char *after_number;
double *value = new double(std::strtod(i, &after_number));
这实际上创建一个 char *
变量,strtod
可以将结束指针放入其中,并将它的地址传递给 strtod
。退出时,after_number
将保存指向停止数字计算的结束字符的指针(希望这将是指向所提供的实际字符串结尾的指针,*after_number == '\0'
.
关于c++ - 使用 std::strtod 后发生奇怪的事情,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39555771/