请解释为什么这个C代码给我一个分段错误?

请解释为什么这个C代码给我一个分段错误?,c,pointers,struct,segmentation-fault,C,Pointers,Struct,Segmentation Fault,我是一个试图学习C语言的初学者。当我运行它时,下面的代码给了我一个分段错误。谁能解释一下原因,或者告诉我我的错误 struct frac sum(struct frac f1, struct frac f2); struct frac { int *numer; int *denom; }; struct frac sum(struct frac f1, struct frac f2) { struct frac rv; *rv.numer = (*f1.numer)*(*f2.denom) +

我是一个试图学习C语言的初学者。当我运行它时,下面的代码给了我一个分段错误。谁能解释一下原因,或者告诉我我的错误

struct frac sum(struct frac f1, struct frac f2);
struct frac {
int *numer;
int *denom;
};
struct frac sum(struct frac f1, struct frac f2) {
struct frac rv;
*rv.numer = (*f1.numer)*(*f2.denom) + (*f2.numer)*(*f1.denom);
*rv.denom = (*f1.denom)*(*f2.denom);
return rv;
}
int main() {
int n = 5;
int d = 10;
struct frac myFrac1 = {&n, &d};
struct frac myFrac2 = {&n, &d};
struct frac myFrac3 = sum(myFrac1, myFrac2);
return 0;
}
试试这个

struct frac sum(struct frac f1, struct frac f2);

struct frac {
    int *numer;
    int *denom;
};

struct frac sum(struct frac f1, struct frac f2) {
    struct frac rv;
    rv.numer = (int*)malloc(sizeof(int));
    rv.denom = (int*)malloc(sizeof(int));
    *rv.numer = (*f1.numer)*(*f2.denom) + (*f2.numer)*(*f1.denom);
    *rv.denom = (*f1.denom)*(*f2.denom);
    return rv;
}

int main() {
    int n = 5;
    int d = 10;

    struct frac myFrac1 = {&n, &d};
    struct frac myFrac2 = {&n, &d};
    struct frac myFrac3 = sum(myFrac1, myFrac2);

    return 0;
}

结果是
rv.numer
rv.denom
在末尾都指向100。

“…代码在运行时给了我一个分段错误。谁能解释原因,或者告诉我错误?”

首先,在调试模式下编译时会出现一些问题,如果您能够看到这些问题,并通过解决每一个问题来做出响应,则可能会防止出现seg故障:

当I编译时,出现正常警告:

不初始化变量是最常被忽略的错误之一,但是程序员(新的和旧的)会犯代价高昂的错误。总是初始化

为什么seg故障-在您的原始代码中,我在运行时看到这一点:


尝试取消引用未初始化的指针几乎总是会导致分段错误

下面是一些解决上述错误的建议:
为了在整个示例中保持可读性,代码的自适应使用
typedef
创建
frac\u s
。以原始帖子的方式使用指针需要动态内存分配,而非指针(即
struct
成员)也同样适用。因此,请注意使用非指针成员。下面的指针使用仅限于函数参数和返回类型
sum(,)
,因此大大简化了代码,但需要动态内存分配和
free()
。将以下内容与代码进行比较,以查看更改的范围

typedef struct  {
    int numer;
    int denom;
}frac_s;


frac_s * sum(frac_s *f1, frac_s *f2);

frac_s * sum(frac_s *f1, frac_s *f2) {
    frac_s * rv = calloc(1, sizeof(*rv)) ;
    if(rv)
    {
        rv->numer = (f1->numer)*(f2->denom) + (f2->numer)*(f1->denom);
        rv->denom = (f1->denom)*(f2->denom);
    }
    return rv;
}

int main(void) {
    int n = 5;
    int d = 10;

    frac_s myFrac1 = {n, d};
    frac_s myFrac2 = {n, d};
    frac_s *myFrac3 = sum(&myFrac1, &myFrac2);
    if(myFrac3)
    {
        //use myFracs;
        free(myFracs);
    }

    return 0;
}

程序将在第二行崩溃

struct frac rv;
*rv.numer = (*f1.numer)*(*f2.denom) + (*f2.numer)*(*f1.denom);
因为,您在堆栈中定义了rv。房车号码可以是任何东西


在大多数情况下,*(rv.numer)是一个你不能写的地方。

你为什么在这里使用指针
rv.numer
rv.denom
未初始化为任何对象,因此取消引用它们是未定义的行为。好的,我从rv.numer和rv.denom中删除了*,但现在我收到警告:“int”中的“int*”赋值会使整数中的指针不带强制转换。如果我尝试将表达式的右侧强制转换为一个指针,如
rv.denom=(int*)((*f1.denom)*(*f2.denom))我收到警告:从不同大小的整数转换为指针。因为您使用的是指针。您需要将
rv.numer
rv.demon
指向某个对象(例如
malloc
调用的结果或指向现有int的指针,就像您在
main
中对其他两个对象所做的那样),或者使用
numer
denom
整数而不是指针。因此,我首先需要将内存分配给
rv.numer
rv.denom
,然后才能让它们指向指针上的某些算术结果?请不要编辑您的原始帖子,从而更改代表该问题本质的内容你的问题是关于什么的。编辑应限于格式化和/或添加新信息以澄清评论中的问题。更改代码会使新观众感到困惑,并导致通过评论和答案提供的内容被误解。出于这个原因,我已经将帖子回滚到原来的版本。这些添加的括号不会改变任何事情
*rv.numer
*(rv.numer)
是等价的。我不这么认为,
*rv.numer
会先做*rv,然后尝试获取numer元素。但是,
*(rv.numer)
将首先找到numer元素,然后在其上执行*。否。看<代码>
(结构和联合成员访问)的优先级高于
*
(间接(取消引用))。该页面甚至给出了一个示例,说明
*p++
如何等效于
*(p++)
,后缀增量运算符与
具有相同的优先级。我不知道您试图对编辑做什么。这是一个C问题,而不是C++问题—您有指针作为结构成员。在存储任何内容之前,需要为它们分配内存。另一个选项是将它们指向已经分配的内存,就像在
struct frac myFrac1={&n,&d}