2015-05-07 37 views
0

我的程序编译没有错误,但是当我运行它时,在输入一个半径等值之后,它会以分段错误退出。带有可变函数参数的分段错误

我已经构建了一个可变数量的参数,但我怀疑它可能与我在“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; 
} 
+1

为什么不使用'double shape_area(double shapetype,double radius,double width)' – wimh

+1

您可以提供样本输入吗?我第一次尝试运行它退出通常与一个不正确的答案,但没有segfaults。 – nmichaels

+1

您是否尝试过使用调试器来帮助您找到问题?它非常适合这些场景。 – kaylum

回答

3

需要初始化使用va_start

double shape_area(double shapetype, ...) 
{ 
va_list args; 
va_start(args,shapetype); 
. 
. 
+0

你死了,我知道我错过了一些基本的东西。我所有的朋友都去睡觉了,明天我的编程考试。谢谢! – Snoviet

+1

...然后,检查每个“if”中的参数,而不是试图概括它们。 Square和circle没有'width'参数。 –

+0

@Snoviet睡觉前请“接受”这个答案! –

1

warzon正确地指出,你需要使用的va_start中的args列表,但这里是如何弄清楚发生了什么事情在未来:

# 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 

您将在此之前触发段错误,或者为您的va_arg查看错误的值。这导致va_args的手册页,其中指出:

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

由于您忘记了调用va_start(),所以应该导致aha时刻。一般来说,如果你得到一个段错误,首先要做的就是启动一个调试器。这很可能会指出你对这个问题的看法。

0

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

如果你想周围的信息传递有关的一些类型之一的形状(你不能使用继承,因为C不是OO),你会更好地创建一个structstructunion 。在你的程序中,不过你也可以制作circle_areasquare_area,rectangle_area并且调用合适的。这也避免了需要记录该说法!

+0

这看起来很像我的作业问题。我怀疑部分任务是“使用可变参数函数”。 – nmichaels

+0

@nmichaels:你很有可能是对的,但让人们陷入这种习惯是一种耻辱。像一个简化的'printf'或连接字符串,直到你看到一个'NULL'将是更可取的! – PJTraill

+0

事实上,我害怕使用1函数,并以这种方式在这个问题中指定。我会自己使用一个数组(就像我最初做的那样,并且未能满足问题要求),并且结构当然也会起作用。从我在其他网站上阅读,我发现可变参数函数是不鼓励的。我的讲师经常使用奇怪的风格,例如递归主要功能来教会我们C可以做什么。但是,你说我相信这不是好的做法。 – Snoviet