我接受了一位科技巨头的电话采访,其中一个问题是这样的:
假设您有一个功能并且在您拥有的功能中
int i = 100;
你在功能中做了一些其他的事情,而没有触摸变量i,稍后你打印我,你看到的值是不同的。什么可能导致变化?
我回答:某种内存损坏,内存溢出......等等。他们似乎并不满意答案。现在我想到堆栈指针搞砸了。有什么我想念的吗?
答案 0 :(得分:2)
在if语句中错误地使用单个等号(赋值)而不是双等号(比较)是一种好方法。
答案 1 :(得分:2)
您在不同的范围使用其他本地i
变量名称(例如,在for
循环,更深的范围,全局声明,模块/函数静态,成员变量,...),等等i
您认为您正在打印出来的不是您实际打印的i
。
另一种可能性 - 参考。另一个引用i
的变量。
答案 2 :(得分:1)
int i = 100
如果您在函数内定义它,它将在STACK变量上。因此,如果以任何方式(.i.e。通过传递具有溢出的参数或函数内的其他局部变量溢出),它可以更改“i”的值。这可能是由于堆栈溢出/损坏而发生的。
但是这样的场景可能导致函数的堆栈指针/返回值损坏,这最终会导致程序崩溃/未定义。
答案 3 :(得分:1)
当函数返回时,i
的那个版本完全消失,因为它是在函数内声明的局部变量,所以它的生命周期与函数有关。在函数外部打印出来的i
版本(之后)是完全不同的i
,在函数之前定义
答案 4 :(得分:1)
这种类型的东西(假设你指的是同一个i,这意味着你打印i的值在同一个函数中)。
#include <stdio.h>
void f()
{
char buf[100];
int i = 100;
int j;
for (j = 0; i <= 100; j++){
buf[j] = 255;
}
printf("i=%d\n", i);
}
int main(int argc, char* argv[])
{
f();
return 0;
}
猜猜是什么印刷的?是的。 I = 255。我试图在这里展示的是,我们可以超出缓冲区并填充后面变量的内容。
更为微妙的做法是滥用sizeof。
e.g。
int array[100]
sizeof array != 100
So you can't do
for (i = 0; i < sizeof array; i++) // very bad!
因此,您可以看到错误如何导致缓冲区溢出。
但是,对于现代版本的gcc,上面的代码将进行核心转储。包括第一个。我必须使用-fno-stack-protector选项实际编译它,以使其在不转储核心的情况下打印结果。如果你做了一个尺寸,它会立即转移核心。
答案 5 :(得分:1)
我回答:某种内存损坏,内存溢出等等。
非常合理的开始。
&#34;没有触及变量i&#34;有点模糊,因为显而易见的i
被触动了,所以我们不得不猜测什么样的触摸不够明显,不能算作触摸。也许:
未定义的行为 :所有投注都已关闭....
引用和指针 :如果创建了非const
引用或指向i
的指针,则可能i
间接修改。它也可能是指向该堆栈地址的悬空指针(但不是&#34;您的&#34; i
)被赋予某些异步中断或其他线程,并且您的i
可以通过其使用来修改。
中断处理 :通常不关心应用程序代码,但如果您编写自己的中断处理程序 - 或尝试某些alpha / beta代码 - 它们可能会意外地搞乱您的堆栈,甚至破坏编译器期望i
可用的寄存器
内联汇编语言 :如果编译器将i
加载到寄存器中,并且您在某些内联汇编中对寄存器执行了某些操作编译器没有推送/保存和弹出/恢复值,i
在打印时似乎已经改变了
off-by-one error 可能导致此问题:
char s[3];
int i = 100;
... do something that loads text into c that might not be terminated ...
s[sizeof s] = '\0'; // "ensure termination" / actually off by one
不可否认,这有点超出&#34;溢出&#34;虽然它不是&#34;很酷&#34;善待fscanf("%s", &s);
,可以任意远远超过s
。
其他想法:
线程可能具有相关性,因为不受审查的语句可能会与i
混淆,但每个线程都有一个单独的堆栈,因此它会采取严重的损坏/未定义的行为
&#34;稍后你打印我&#34; - 我认为它不是他们正在寻找的东西,但是有一种方法可以填补这个问题:用十六进制打印和思考值64与预期的100小数不同,从另一个范围打印i
,&#34;干扰&#34;来自其他印刷语句(可能在其他线程中),例如打印&#34; 0&#34;使i
似乎是&#34; 1000&#34;