请解释为啥这个 C 代码给我一个分段错误?
Posted
技术标签:
【中文标题】请解释为啥这个 C 代码给我一个分段错误?【英文标题】:Please explain why this C code gives me a segmentation fault?请解释为什么这个 C 代码给我一个分段错误? 【发布时间】:2021-05-24 23:42:13 【问题描述】:我是一名尝试学习 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;
【问题讨论】:
你为什么在这里使用指针?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
ints 而不是指针。
所以我首先需要为rv.numer
和rv.denom
分配内存,然后才能让它们指向指针上的一些算术结果?
请不要编辑您的原始帖子以更改代表您问题本质的内容。编辑应仅限于格式化和/或添加新信息以澄清 cmets 中的问题。更改代码会导致新查看者感到困惑,并导致已通过 cmets 提供的内容和答案被误解。出于这个原因,我已将帖子回滚到原来的位置。
【参考方案1】:
程序会在第二行崩溃
struct frac rv;
*rv.numer = (*f1.numer)*(*f2.denom) + (*f2.numer)*(*f1.denom);
因为,您在堆栈中定义了 rv。 rv.number 可以是任何东西。
在大多数情况下,*(rv.numer) 是你不能写的地方。
【讨论】:
【参考方案2】:"...当我运行它时,代码给了我一个分段错误。谁能解释原因,或者告诉我我的错误"
首先,如果在调试模式下编译,可能会出现一些问题,如果您能够看到它们并通过解决每个问题做出响应,可能会阻止您遇到段错误:
当我编译时出现正常警告:
不初始化变量是程序员(新老)最常被忽略但代价高昂的错误之一。始终初始化。
为什么会出现段错误 - 在您的原始代码中,我在 运行 时看到了这个:
尝试取消引用未初始化的指针几乎总是会导致分段错误。
只是一些可以解决上述错误的建议:
为了在整个示例改编中保持可读性,您的代码使用typedef
创建frac_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;
【讨论】:
【参考方案3】:试试这个
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。
【讨论】:
这些添加的括号不会改变任何东西。*rv.numer
和 *(rv.numer)
是等价的。
我不这么认为,*rv.numer
会先做 *rv 然后尝试获取 numer 元素。但是,*(rv.numer)
会先找到 numer 元素,然后对其执行 *。
没有。见en.cppreference.com/w/c/language/operator_precedence。 .
(结构和联合成员访问)的优先级高于*
(间接(取消引用))。该页面甚至给出了*p++
等效于*(p++)
的示例,并且后缀递增运算符具有与.
相同的优先级
我不知道你想用你的编辑做什么。这是一个 C 问题,而不是 C++
你有指针作为你的结构成员。他们需要先分配内存,然后才能存储任何内容。另一种选择是将它们指向已分配的内存,就像您在 struct frac myFrac1 = &n, &d;
中所做的那样以上是关于请解释为啥这个 C 代码给我一个分段错误?的主要内容,如果未能解决你的问题,请参考以下文章