【问题标题】:Segmentation fault with variable function arguments具有可变函数参数的分段错误
【发布时间】:2015-07-18 14:57:06
【问题描述】:

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

我将它构造为采用可变数量的参数,但我怀疑这可能与我在“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;
}

【问题讨论】:

  • 为什么不使用double shape_area(double shapetype, double radius, double width)
  • 你能提供样本输入吗?我第一次尝试运行它时以错误的答案正常退出,但没有段错误。
  • 您是否尝试过使用调试器帮助您找到问题?它非常适合这些场景。
  • 值得注意的是,此功能通常不能满足功能要求(正如我在回答中所说),但在练习中明确要求它。如果您(一个)不需要这样做,请不要这样做!

标签: c variables segmentation-fault arguments


【解决方案1】:

你需要使用va_start初始化args列表

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

【讨论】:

  • 你说得对,我知道我错过了一些基本的东西。我所有的朋友都睡觉了,我的编程考试是明天。谢谢!
  • ... 然后,检查每个 if 中的参数,而不是试图概括它们。方形和圆形没有width 参数。
  • @Snoviet 睡前请“接受”这个答案!
【解决方案2】:

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

您可能会在此之前遇到段错误,或者看到您的 va_arg 的值不正确。这导致了 va_args 的手册页,其中指出:

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

这应该会导致一个令人惊叹的时刻,因为你忘记调用 va_start()。一般来说,如果遇到段错误,首先要做的是启动调试器。它很可能会为您指出问题所在。

【讨论】:

    【解决方案3】:

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

    如果您想传递有关多种类型之一的形状的信息(并且您不能使用继承,因为 C 不是 OO),您最好创建 structunion structs。但是,在您的程序中,您也可以创建circle_areasquare_arearectangle_area 并调用相应的。这也消除了记录 shapetype 参数的需要!

    【讨论】:

    • 这对我来说很像一个家庭作业问题。我怀疑部分任务是“使用可变参数函数”。
    • @nmichaels:你很有可能是对的,但是让人们养成这样的习惯真是太可惜了。像简化的 printf 或连接字符串直到看到 NULL 会更好!
    • 确实,恐怕使用 1 个函数,并且在这个问题中指定了这种方式。我自己会使用一个数组(就像我最初那样,但未能满足问题要求),一个结构当然也可以工作。从我在其他网站上的阅读中,我发现不鼓励使用可变参数函数。我的讲师经常使用诸如递归主函数之类的奇怪风格来教我们C可以做什么。但我喜欢你说我认为这不是好的做法。
    猜你喜欢
    • 1970-01-01
    • 2013-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多