C 在该程序的哪一点,我们将收到分段错误?

C 在该程序的哪一点,我们将收到分段错误?,c,C,我得到了下面的代码,并被问到在什么时候我们会得到一条消息,说分割错误已经发生 #include <stdlib.h> #include <string.h> #include <stdio.h> struct N { struct N *n; char *q; int a; } *q; int foo(void) { N *p = malloc(sizeof *p); p->a = 42; p->q = "life,␣universe,

我得到了下面的代码,并被问到在什么时候我们会得到一条消息,说分割错误已经发生

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
struct N {
 struct N *n;
 char *q;
 int a;
} *q;
int foo(void) {
 N *p = malloc(sizeof *p);
 p->a = 42;
 p->q = "life,␣universe,␣everything";
 p->n = (struct N *)p;
 q = p;
 free(p);
 return 1;
}

int main() {
 free( strcpy((char *)malloc(20),foo() + "Hello,␣World\n"));
 (void) printf("q=%p\n", q);
 (void) printf("q->a=%d\n", q->a);
 (void) printf("q->q=%s\n", q->q);
 return 0;
}
#包括
#包括
#包括
结构{
结构N*N;
char*q;
INTA;
}*q;
int foo(无效){
N*p=malloc(sizeof*p);
p->a=42;
p->q=“生活,␣宇宙,␣“一切”;
p->n=(结构n*)p;
q=p;
自由基(p);
返回1;
}
int main(){
free(strcpy((char*)malloc(20),foo()+“你好,␣世界),;
(无效)printf(“q=%p\n”,q);
(void)printf(“q->a=%d\n”,q->a);
(void)printf(“q->q=%s\n”,q->q);
返回0;
}
答案是,它只会发生在主体部分中倒数第二行之后,
(void)printf(“q->q=%s\n”,q->q)

有人能确切地解释一下为什么会发生这种情况吗


非常感谢。

一个更正确的表达问题的方式是“程序的行为何时变得未定义”,或者“分段错误可能发生的第一个位置是什么”

因此,要回答这个问题:

以这一行为例:
free(strcpy((char*)malloc(20),foo()+“你好,␣世界),

编辑(删除此项):此行不敏感。将
int
添加到文本
char*
并不意味着什么。我的C编译器发出警告并继续运行,所以我也会这样做

编辑(添加此项):正如注释中指出的,
foo()
返回1,因此这将传递给
“ello,␣World\n“
到strcpy。这是可以的,因为这少于分配的20个字符。这在我的C编译器中是一个警告,因为它很奇怪

问题是:这是否少于20字节。我认为是这样?因此,这一行基本上只是具有调用
foo()

foo
只是乱七八糟的代码——但我会在其中添加注释,看看其中是否有未定义的部分:

int foo(void) {
 // This is defined (added struct so it compiles)
 struct N *p = malloc(sizeof *p);

 // This is defined
 p->a = 42;

 // This is defined
 p->q = "life,␣universe,␣everything";

 // This is defined
 p->n = (struct N *)p;

 // This is defined
 q = p;

 // This is defined
 free(p);

 // Right now, q is pointing at free space -- it is very bad to derefence q
 return 1;
}
返回到
main()

(void)printf(“q=%p\n”,q)

这将打印
q
指针值——它不是解引用,因此没有问题

(void)printf(“q->a=%d\n”,q->a)

我说这是没有定义的。显然,您正在解引用指向可用空间的
q
q->a
是自由空间中的整数大小的位置,您正在阅读它。现在,如果内存没有被回收,这可能不是故障。它仍然不正确,也没有定义

现在,我们进入一条线路,您被告知will segfault:

(void)printf(“q->q=%s\n”,q->q)

这是未定义的,原因与
q->a
相同

当我运行它时,我得到

q=0x7fc30f4017c0
q->a=2
Segmentation fault: 11
所以,你看:它没有为q->a打印42,也没有进入下一行。程序没有定义,并且做了它允许做的事情之一,这是它想要做的任何事情。比如说

  • 它可能打印错误的号码
  • 它可能有故障
  • 它可以完美地工作
  • 它可能是一个安全漏洞的载体,它接管了你的机器,让黑客访问你的银行账户
  • 这更好地解释了这一点:


    更多:

    一个更正确的表达问题的方式是“程序的行为何时变得未定义”,或者“分段错误可能发生的第一个位置是什么”

    因此,要回答这个问题:

    以这一行为例:
    free(strcpy((char*)malloc(20),foo()+“你好,␣世界),

    编辑(删除此项):此行不敏感。将
    int
    添加到文本
    char*
    并不意味着什么。我的C编译器发出警告并继续运行,所以我也会这样做

    编辑(添加此项):正如注释中指出的,
    foo()
    返回1,因此这将传递给
    “ello,␣World\n“
    到strcpy。这是可以的,因为这少于分配的20个字符。这在我的C编译器中是一个警告,因为它很奇怪

    问题是:这是否少于20字节。我认为是这样?因此,这一行基本上只是具有调用
    foo()

    foo
    只是乱七八糟的代码——但我会在其中添加注释,看看其中是否有未定义的部分:

    int foo(void) {
     // This is defined (added struct so it compiles)
     struct N *p = malloc(sizeof *p);
    
     // This is defined
     p->a = 42;
    
     // This is defined
     p->q = "life,␣universe,␣everything";
    
     // This is defined
     p->n = (struct N *)p;
    
     // This is defined
     q = p;
    
     // This is defined
     free(p);
    
     // Right now, q is pointing at free space -- it is very bad to derefence q
     return 1;
    }
    
    返回到
    main()

    (void)printf(“q=%p\n”,q)

    这将打印
    q
    指针值——它不是解引用,因此没有问题

    (void)printf(“q->a=%d\n”,q->a)

    我说这是没有定义的。显然,您正在解引用指向可用空间的
    q
    q->a
    是自由空间中的整数大小的位置,您正在阅读它。现在,如果内存没有被回收,这可能不是故障。它仍然不正确,也没有定义

    现在,我们进入一条线路,您被告知will segfault:

    (void)printf(“q->q=%s\n”,q->q)

    这是未定义的,原因与
    q->a
    相同

    当我运行它时,我得到

    q=0x7fc30f4017c0
    q->a=2
    Segmentation fault: 11
    
    所以,你看:它没有为q->a打印42,也没有进入下一行。程序没有定义,并且做了它允许做的事情之一,这是它想要做的任何事情。比如说

  • 它可能打印错误的号码
  • 它可能有故障
  • 它可以完美地工作
  • 它可能是一个安全漏洞的载体,它接管了你的机器,让黑客访问你的银行账户
  • 这更好地解释了这一点:


    更多信息:

    为了补充@Lou Franco的出色回答,我认为无论是谁提出这个问题,都会得到以下答案:

    p->q = "life,␣universe,␣everything";
    
    如果执行
    (void)printf(“q=%lu\n”,sizeof(q->q)),则将
    字符串
    (在C中
    常量char*
    )分配给未正确分配内存的结构中的指针,这只是指向char的指针
    在大多数情况下(取决于系统),您会得到8,这是指向
    char
    的指针的大小(分配的字节数),那么
    q->q
    需要更多的字节,13似乎是我的测试允许的较小的大小,因此是