0

为什么此代码在定期运行时产生段错误,但未定义的行为而不是段错误,如果我添加命令行参数或注释掉调用cpy函数?指针段错误与未定义的行为

#include <cstdlib> 
#include <iostream> 
#include <cstring> 
using namespace std; 

int *p; 

void fn() { 
    int n[1]; 
    n[0]=99; 
    p = n; 

} 

void cpy(char *v) { 
    char x[8]; 
    strncpy(x,v,8); 
} 

int main(int argc, char** argv) { 
    fn(); 
    cpy(argv[1]); 
    cout << "p[0]:" << p[0]; 
} 

我知道n是功能fn一个局部变量,但有一个方法可以让我缓冲区溢出或输入的东西如argv[1]得到它的打印值不管它是举行n /是在记忆中?

+2

未定义的行为?如果添加命令行参数,它将存储在argv [1]中。如果你注释掉了cpy()行,那么你并没有在任何地方使用argv [1],这就是导致段错误的原因。 – Matt

+0

但为什么不使用'argv [1]'会导致段错误?我的意思是未定义的行为,打印指向超出范围变量的'p'的索引。 – Austin

+0

等待,因为不提供cmdline参数,或不使用变量argv [1]? – Matt

回答

2

如果你没有通过一个参数,那么argv[1]==nullptr。然后cpy(argv[1])cpy(nullptr),并且cpy调用strncpy(x,nullptr,8)和段错误。

如果你注释掉了cpy,那么没有段错误。

如果你传递一个参数,那么cpy将不会segfault。但是,你会遇到一个不同的问题:fn确实是p=n,但是n被声明在堆栈中,因此返回主cout<<p[0],p指向不再存在的对象n,因此行为未定义。

+0

谢谢你解释我95%的困惑。知道一种方法来操纵输入,以便从'num'所在的位置打印出数据,如果它没有被覆盖? – Austin

+0

当你说'num'时,你的意思是在n中声明的n []吗?您需要在fn返回之前将其打印出来,或者在fn返回之前将其保存在其他位置。 – Waxrat

+0

对不起''[]'我基本上是在不改变代码的情况下让主打印出'99'。 – Austin