带有变量函数参数的分段错误

时间:2015-05-07 20:35:57

标签: c variables segmentation-fault arguments

我的程序编译时没有错误,但是当我运行它时,在输入半径值之后,它会因分段错误而退出。

我构造它来获取可变数量的参数,但我怀疑它可能与我在“shape_area”函数操作期间调用每个参数的方式有关。

有人可以帮忙解释我在这里做错了吗?

#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 个答案:

答案 0 :(得分:3)

您需要使用va_start

初始化args列表
double shape_area(double shapetype, ...)
{
va_list args;
va_start(args,shapetype);
.
.

答案 1 :(得分:1)

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

你要么在那之前点击segfault,要么看到你的va_arg值不正确。这导致了va_args的手册页,其中指出:

  

参数ap是由va_start()初始化的va_list ap。

这应该导致aha时刻,因为你忘了打电话给va_start()。一般来说,如果你遇到段错误,首先要做的就是启动一个调试器。它很可能会指出你正确的问题。

答案 2 :(得分:0)

在我看来,你所做错的是将所有不同的公式塞进一个函数中。当然,在这种情况下,@ warzon是正确的,你需要va_start,但我认为这种方法没有任何优势,除非可以想象,问题要求你使用它。 shape_area中的大多数共享代码都与va_list机制的开销有关!

如果您想传递有关多种类型之一的形状的信息(并且您不能使用继承,因为C不是OO),您最好创建struct或{ {1}}的{​​1}}。在您的计划中,您也可以unionstructcircle_area并拨打相应的电话。这也消除了记录square_area参数的必要性。