【发布时间】:2016-06-11 20:44:06
【问题描述】:
我正在做 K&R 书中的练习,在尝试扩展 04-06 以允许具有字符串名称的变量时遇到了一个奇怪的错误。说实话,我实际上已经设法修复了这个错误(很简单——下面解释),但我想知道为什么会首先发生错误。
对于那些不熟悉这个问题的人,你基本上会被要求创建一个命令行计算器(使用波兰符号),它可以存储和调用带有字符名称的变量。
这是出现问题的相关代码:
#define MAXOPLEN 1000
int varCount = 1;
char **keys;
char **values;
// changing the declaration to:
// char strOps[][STROPCOUNT] = { ... };
// fixed the issue
char *strOps[STROPCOUNT] = { "dupe", "swap", "del", "print",
"clr", "sin", "cos", "tan",
"exp", "pow", "ln", "log",
"mem", "re"};
main() {
keys = malloc(varCount * sizeof(char[MAXOPLEN]));
keys[0] = "ans";
values = malloc(varCount * sizeof(char[MAXOPLEN]));
values[0] = "0.0";
... // Other stuff related to the program
}
// flag is unrelated to the problem I'm asking about. It just checks to see
// if the variable name used to store value n is 'ans', which is where
// the last returned value is stored automatically
void memorize(char s[], double n, bool flag) {
... // small conditional block for flag
for (i = 0; i < varCount; i++) {
if (equals(keys[i], s)) {
found = True;
// Next line is where the program actually breaks
snprintf(values[i], MAXOPLEN, "%f", n);
break;
}
}
if (!found) {
i = varCount;
varCount++;
keys = realloc(keys, varCount * sizeof(char*));
keys[i] = malloc(sizeof(char[MAXOPLEN]));
keys[i] = s;
values = realloc(values, varCount * sizeof(char*));
values[i] = malloc(sizeof(char[MAXOPLEN]));
snprintf(values[i], MAXOPLEN, "%f", n);
}
}
编译运行后,第一次输入方程进行计算,一切似乎都运行的很顺利。但是,在调试时,我发现 strOps 中的前三个 char* 奇怪地指向不同的地址。当试图将等式的返回值保存到“ans”时,它进入 memorize() 中的 for 循环,试图查看字符串 s 是否已经被用作键名。它正确地找到keys[0]指向一个匹配s的值(“ans”)的字符串,然后尝试将double n转换为一个字符串并将其保存在values[0]中。
在 snprintf() 函数内部时,strOps 中的前三个 char* 指向 corecrt_stdio_config.h 中此方法内部的其他位置:
_Check_return_ _Ret_notnull_
__declspec(noinline) __inline unsigned __int64* __CRTDECL __local_stdio_printf_options(void)
{
// Error occurs after this next line:
static unsigned __int64 _OptionsStorage;
return &_OptionsStorage;
}
如上面代码中所述,将 strOps 设为 2D 字符数组(而不是 char 指针数组)解决了该问题。这是有道理的,因为字符数组不能改变单个字符的值,但我不明白为什么 corecrt_stdio_config.h 中的那个方法首先改变了这三个指针的值。
谢谢!
【问题讨论】:
-
开始使用正确的原型函数声明符。
main()已弃用。并且使用更新的书,K&R 已经过时了。它不教现代C!并查看How to Ask,提供minimal reproducible example。即使您的代码在没有警告的情况下编译,也没有任何意义。 -
并检查函数的结果是否与进一步执行相关!
realloc可能会失败!