可变函数参数的分段错误
Segmentation fault with variable function 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;
}
您需要使用 va_start
初始化 args 列表
double shape_area(double shapetype, ...)
{
va_list args;
va_start(args,shapetype);
.
.
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
= 0
你要么在那之前遇到段错误,要么看到你的 va_arg 的值不正确。这导致 va_args 的手册页,其中指出:
The argument ap is the va_list ap initialized by va_start().
这应该会带来惊喜时刻,因为您忘记调用 va_start()。一般来说,如果遇到段错误,要做的第一件事就是启动调试器。它很可能会指出您的问题所在。
在我看来,您做错的是将所有不同的公式塞进了一个函数中。当然,@warzon 在这种情况下您需要 va_start
是正确的,但我认为这种方法没有任何优势,除非可以想象,问题要求您使用它。 shape_area
中的大部分共享代码都与 va_list
机制的开销有关!
如果您想传递有关多种类型之一的形状的信息(并且您不能使用继承,因为 C 不是面向对象的),您最好创建一个 struct
或union
个 struct
个。但是,在您的程序中,您也可以制作 circle_area
、square_area
、rectangle_area
并调用适当的。这也避免了记录 shapetype
参数的需要!
我的程序编译没有错误,但是当我运行它时,在我输入一个像半径这样的值后它以分段错误退出。
我将其构造为接受可变数量的参数,但我怀疑这可能与我在 "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;
}
您需要使用 va_start
初始化 args 列表double shape_area(double shapetype, ...)
{
va_list args;
va_start(args,shapetype);
.
.
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
= 0
你要么在那之前遇到段错误,要么看到你的 va_arg 的值不正确。这导致 va_args 的手册页,其中指出:
The argument ap is the va_list ap initialized by va_start().
这应该会带来惊喜时刻,因为您忘记调用 va_start()。一般来说,如果遇到段错误,要做的第一件事就是启动调试器。它很可能会指出您的问题所在。
在我看来,您做错的是将所有不同的公式塞进了一个函数中。当然,@warzon 在这种情况下您需要 va_start
是正确的,但我认为这种方法没有任何优势,除非可以想象,问题要求您使用它。 shape_area
中的大部分共享代码都与 va_list
机制的开销有关!
如果您想传递有关多种类型之一的形状的信息(并且您不能使用继承,因为 C 不是面向对象的),您最好创建一个 struct
或union
个 struct
个。但是,在您的程序中,您也可以制作 circle_area
、square_area
、rectangle_area
并调用适当的。这也避免了记录 shapetype
参数的需要!