对于一些背景知识,我正在用C编写一个抄表应用程序,用于运行专有版本DOS的小型16位掌上电脑.
我有一个显示仪表信息的屏幕,并提示用户输入读数.当用户按下设备上的回车键时,将执行以下代码:
/* ...
* beginning of switch block to check for keystrokes
* ...
*/
case KEY_ENTER: {
/* show what has been entered */
if(needNew == 0) {
/* calculate usage for new reading */
double usg = 0;
int ret = CalculateNewUsage(vlr, buf, &usg);
VerifyReadScreen(vlr, ret, buf, &usg);
needRedraw = TRUE;
}
break;
}
/* .... end switch statement */
Run Code Online (Sandbox Code Playgroud)
vlr是一个指针,它指向包含所有帐户/米信息,一个结构buf是类型的char[21]用于存储数值击键针对其该块上面处理的读数.当我在调用之前和之后检查它们时,我的变量都包含有效数据CalculateNewUsage.
但是,当我在输入后再次检查可变数据时VerifyReadScreen,newread会在内存中随机指向并返回看起来像版权声明的内容.有趣的是无论什么账户或阅读什么我进入-对同一无效数据newread中VerifyReadScreen印在屏幕上.我以VerifyReadScreen同样的方式传递地址CalculateNewUsage,但不知怎的,我最终得到了不同的东西.
这是VerifyReadScreen:
BYTE VerifyReadScreen(const VLRREC * vlr,
const int status,
const char * newread,
const double * usage) {
/* snip a whole bunch of irrelevant formatting code */
printf("%s", (*newread)); /* prints funky copyright text */
/* snip more irrelevant formatting code */
return TRUE;
}
Run Code Online (Sandbox Code Playgroud)
谢谢Jefromi的指出我在哪里实际打印的代码newread中VerifyReadScreen应认真阅读:
printf("%s", newread); /* yay! */
Run Code Online (Sandbox Code Playgroud)
因为我不需要解除引用,newread因为printf这对我来说.我本质上是将一个指针传递给一个指针,该指针在内存中是一个任意的位置.
我想我有足够的信心发布这个答案:
BYTE VerifyReadScreen(const VLRREC * vlr, const int status, const char * newread, const double * usage) {
...
LCD_set_cursor_pos(19 - strlen(newread), 3);
printf("%s", (*newread)); /* prints funky copyright text */
...
}
Run Code Online (Sandbox Code Playgroud)
你有一个字符串(char*)newread,但在那个printf中,你取消引用它,它给你字符串的第一个字符.然后使用它作为%sfor printf 的参数,因此它会尝试转到该字符给出的内存地址并打印它在那里找到的内容.
PS你运气不好 - 一般来说,做这样的事情可能会给你一个段错误,所以你可以跟踪它到那一行,并意识到那里有一个指针错误.