My program compiles without error, but when I run it, it quits with a segmentation fault after I input a value such a radius.
我的程序编译没有错误,但是当我运行它时,它输入一个像半径的值后退出分段错误。
I have it constructed to take a variable amount of arguments, but I suspect it could be something to do with the way I call each argument during the operation of the "shape_area" function.
我构造它来获取可变数量的参数,但我怀疑它可能与我在“shape_area”函数操作期间调用每个参数的方式有关。
Can anybody help explain what I am doing wrong here?
任何人都可以帮助解释我在这里做错了什么吗?
#include <stdio.h>
#include <math.h>
#include <stdarg.h>
double shape_area(double shapetype, ...);
int main(void)
{
int shapetype;
double radius, side, length, width, area;
printf("\n\nPlease enter the type of shape you wish to get the area of:\n");
printf("| 1-Circle | 2-Square | 3-Rectangle |\n");
scanf("%d", &shapetype);
// Circle
if(shapetype == 1)
{
printf("\nPlease enter the radius of your circle: ");
scanf("%lf", &radius);
area = shape_area(shapetype, radius);
}
// Square
else if(shapetype == 2)
{
printf("\nPlease enter the side length of your square: ");
scanf("%lf", &side);
area = shape_area(shapetype, side);
}
// Rectangle
else if(shapetype == 3)
{
printf("\nPlease enter the side length of your square: ");
scanf("%lf", &length);
printf("\nPlease enter the side length of your square: ");
scanf("%lf", &width);
area = shape_area(shapetype, length, width);
}
else
{
printf("\n\nInvalid Input!\n");
return (0);
}
printf("\n\nArea of Shape: %lf\n\n", area);
return (0);
}
double shape_area(double shapetype, ...)
{
va_list args;
double temparea;
double radius;
double side;
double length;
double width;
radius = va_arg (args, double);
side = radius;
length = radius;
width = va_arg (args, double);
if(shapetype == 1)
{
temparea = M_PI*radius*radius;
}
if(shapetype == 2)
{
temparea = side*side;
}
if(shapetype == 3)
{
temparea = length*width;
}
va_end (args);
return temparea;
}
3 个解决方案
#1
You need to initialize the args list using va_start
您需要使用va_start初始化args列表
double shape_area(double shapetype, ...)
{
va_list args;
va_start(args,shapetype);
.
.
#2
warzon correctly pointed out that you need to use va_start, but here's how to figure out what's going on in the future:
warzon正确地指出你需要使用va_start,但这里是如何弄清楚将来会发生什么:
# The -g is the important part here, -O0 will help too if you don't care about optimization.
$ gcc -Wall -std=gnu99 -O0 -Wextra -Werror -g -foptimize-sibling-calls -o shape shape.c
$ gdb ./shape
...
(gdb) b shape_area # Set a breakpoint.
Breakpoint 1 at 0x80485b8: file shape.c, line 63.
(gdb) run
Please enter the type of shape you wish to get the area of:
| 1-Circle | 2-Square | 3-Rectangle |
1
Please enter the radius of your circle: 3
63 radius = va_arg (args, double);
(gdb) next # Run the line that assigns the radius.
65 side = radius;
(gdb) p radius
$1 = 0
You'll either hit the segfault before there, or see an incorrect value for your va_arg. That leads to the man page for va_args, which states:
您可以在那之前点击segfault,或者看到va_arg的值不正确。这导致va_args的手册页,其中指出:
The argument ap is the va_list ap initialized by va_start().
参数ap是由va_start()初始化的va_list ap。
That ought to lead to the aha moment, since you forgot to call va_start(). In general, if you're getting a segfault, the first thing to do is fire up a debugger. It will most likely point you right at the problem.
这应该导致aha时刻,因为你忘了打电话给va_start()。一般来说,如果你遇到段错误,首先要做的就是启动一个调试器。它很可能会指出你正确的问题。
#3
What you are doing wrong is, in my opinion, jamming all the different formulae into one function. Of course, @warzon is right that you need va_start
in this case, but I see no advantage to this approach, unless, conceivably, you are required by the question to use it. Most of the shared code in shape_area
relates to the overhead of the va_list
mechanism!
在我看来,你所做错的是将所有不同的公式都塞进一个函数中。当然,@ warzon是正确的,在这种情况下你需要va_start,但我认为这种方法没有任何优势,除非,可以想象,问题要求你使用它。 shape_area中的大多数共享代码都与va_list机制的开销有关!
If you want to pass around information about a shape of one of a number of types (and you can’t use inheritance because C is not OO), you would be better to create a struct
or a union
of struct
s. In your programme, however you could just as well make circle_area
, square_area
, rectangle_area
and call the appropriate one. This also obviates the need to document that shapetype
argument!
如果要传递有关多种类型之一的形状的信息(并且您不能使用继承,因为C不是OO),那么最好创建结构或结构的并集。在你的程序中,你也可以创建circle_area,square_area,rectangle_area并调用相应的一个。这也消除了记录shapetype参数的需要!
#1
You need to initialize the args list using va_start
您需要使用va_start初始化args列表
double shape_area(double shapetype, ...)
{
va_list args;
va_start(args,shapetype);
.
.
#2
warzon correctly pointed out that you need to use va_start, but here's how to figure out what's going on in the future:
warzon正确地指出你需要使用va_start,但这里是如何弄清楚将来会发生什么:
# The -g is the important part here, -O0 will help too if you don't care about optimization.
$ gcc -Wall -std=gnu99 -O0 -Wextra -Werror -g -foptimize-sibling-calls -o shape shape.c
$ gdb ./shape
...
(gdb) b shape_area # Set a breakpoint.
Breakpoint 1 at 0x80485b8: file shape.c, line 63.
(gdb) run
Please enter the type of shape you wish to get the area of:
| 1-Circle | 2-Square | 3-Rectangle |
1
Please enter the radius of your circle: 3
63 radius = va_arg (args, double);
(gdb) next # Run the line that assigns the radius.
65 side = radius;
(gdb) p radius
$1 = 0
You'll either hit the segfault before there, or see an incorrect value for your va_arg. That leads to the man page for va_args, which states:
您可以在那之前点击segfault,或者看到va_arg的值不正确。这导致va_args的手册页,其中指出:
The argument ap is the va_list ap initialized by va_start().
参数ap是由va_start()初始化的va_list ap。
That ought to lead to the aha moment, since you forgot to call va_start(). In general, if you're getting a segfault, the first thing to do is fire up a debugger. It will most likely point you right at the problem.
这应该导致aha时刻,因为你忘了打电话给va_start()。一般来说,如果你遇到段错误,首先要做的就是启动一个调试器。它很可能会指出你正确的问题。
#3
What you are doing wrong is, in my opinion, jamming all the different formulae into one function. Of course, @warzon is right that you need va_start
in this case, but I see no advantage to this approach, unless, conceivably, you are required by the question to use it. Most of the shared code in shape_area
relates to the overhead of the va_list
mechanism!
在我看来,你所做错的是将所有不同的公式都塞进一个函数中。当然,@ warzon是正确的,在这种情况下你需要va_start,但我认为这种方法没有任何优势,除非,可以想象,问题要求你使用它。 shape_area中的大多数共享代码都与va_list机制的开销有关!
If you want to pass around information about a shape of one of a number of types (and you can’t use inheritance because C is not OO), you would be better to create a struct
or a union
of struct
s. In your programme, however you could just as well make circle_area
, square_area
, rectangle_area
and call the appropriate one. This also obviates the need to document that shapetype
argument!
如果要传递有关多种类型之一的形状的信息(并且您不能使用继承,因为C不是OO),那么最好创建结构或结构的并集。在你的程序中,你也可以创建circle_area,square_area,rectangle_area并调用相应的一个。这也消除了记录shapetype参数的需要!