【问题标题】:Issue with program output程序输出问题
【发布时间】:2015-07-01 03:39:08
【问题描述】:

下面是我的程序,它在给定一定数量的 (x,y) 坐标的情况下确定多边形的周长和面积,但我似乎得到了错误的输出,我不明白为什么。

输入是:

  3  12867  1.0 2.0  1.0 5.0  4.0 5.0
  5  15643  1.0 2.0  4.0 5.0  7.8 3.5  5.0 0.4  1.0 0.4

第一个条目是点(点)的数量,第二个条目是多边形 ID,之后的任何内容都是一组坐标。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define MAX_PTS 100
#define MAX_POLYS 100
#define END_INPUT 0

struct Point {
    double x, y;
};

double getDistance(struct Point a, struct Point b) {
    double distance;
    distance = sqrt((a.x - b.x) * (a.x - b.x) + (a.y-b.y) *(a.y-b.y));
    return distance;
}

double polygon_area(int length, double x[], double y[]) {
    double area = 0.0;
    for (int i = 0; i < length; ++i) {
       int j = (i + 1) % length;
       area += (x[i] * y[j] - x[j] * y[i]);
    }
area = area / 2;
area = (area > 0 ? area : -1 * area);

return (area);
}

int main(int argc, char *argv[]) {
    int npoints, poly_id;
    struct Point a, b;

    if(scanf("%d %d", &npoints, &poly_id)) {
        int iteration = 0;
        scanf("%lf %lf", &a.x, &a.y);
        struct Point initialPoint = a;
        double perimeter = 0;  // i start with 0 value of parameter.     
        for (iteration = 1; iteration < npoints; ++iteration) {
            scanf("%lf %lf", &b.x, &b.y);  // take input for new-point.
            perimeter += getDistance(a, b); // add the perimeter.
        // for next iteration, new-point would be first-point in getDistance
            a = b; 
        }
        // now complete the polygon with last-edge joining the last-point
        // with initial-point.
        perimeter += getDistance(a, initialPoint);

        printf("First polygon is %d\n", poly_id);
        printf("perimeter = %2.2lf m\n", perimeter);

        scanf("%d %d", &npoints, &poly_id);
        double x[MAX_PTS], y[MAX_PTS];
        double area = 0;
        for (iteration = 0; iteration < npoints; ++iteration) {
            scanf("%lf %lf", &(x[iteration]), &(y[iteration]));
        }
        area = polygon_area(npoints, x, y); 

        printf("First polygon is %d\n", poly_id);
        printf("area = %2.2lf m^2\n", area);

    } else if(scanf("%d", &npoints)==0) {
        exit(EXIT_SUCCESS);
    }

    return 0;
}

我不断得到的输出是:

First polygon is 12867
perimeter = 10.24 m
First polygon is 15643
area = 19.59 m^2

但我想要的输出是:

First polygon is 12867
perimeter = 10.24 m
First polygon is 12867
area = 4.50 m^2 

或者:

First polygon is 12867
perimeter = 10.24 m
area = 4.50 m^2

如果有人能指出我哪里出错了,将不胜感激。

【问题讨论】:

  • 我建议学习如何使用调试器。这个想法是逐行检查你的代码并检查变量,直到你发现错误。另一种方法是在战略点使用printf 输出值。
  • 在计算第一个多边形的面积之前,您正在读取第二个多边形。将第一个多边形的坐标读入一个数组,这样您就可以计算周长和面积。
  • 你的问题标题说输出有问题,但实际上并不是问题。问题显然出在代码上,而不是输出问题。当有人阅读问题标题时,这不是他们所期望的问题。
  • 这是垃圾输入/垃圾输出代码或数据问题。如果您确定您的第一个多边形区域在其 3 个点的情况下是正确的,那么它似乎指向 5 点多边形的数据不好。我不知道您对代码有什么期望,但它似乎在polygon_area 中没有任何明显的语法类型错误。您可以再次检查您的计算——也许在 3 点测试中未使用或最小化的一个方面确实存在逻辑问题,在进行 5 点计算之前不是问题。仔细检查数据和计算。

标签: c arrays loops struct polygons


【解决方案1】:

如果你还没有整理出来,那你的问题就很明显了。您读取第一个多边形的数据,然后计算perimeter

    perimeter += getDistance(a, initialPoint);

    printf("First polygon is %d\n", poly_id);
    printf("perimeter = %2.2lf m\n", perimeter);

然后,莫名其妙地,您在计算面积之前读取了第二个多边形的数据:

    scanf("%d %d", &npoints, &poly_id);
    double x[MAX_PTS], y[MAX_PTS];
    double area = 0;
<snip>
    area = polygon_area(npoints, x, y); 

您希望如何使用第二个多边形的数据来获取第一个多边形的面积有点令人困惑。

您需要做的是计算每个多边形的perimeterarea,然后再读取下一个多边形的数据。您通常会提示输入 number of polygons 进行处理,然后执行以下操作,而不是您的 if 代码块:

for (i = 0; i < npolys; i++)
{
    <read data for poly>
    <calculate perimeter>
    <calculate area>
    <display results>
}

接下来,当您期望用户提供数据时,提示输入。不要只让用户看着闪烁的光标想知道您的程序是否挂起等。一个简单的printf 询问点数和多边形ID 工作正常。然后,输入每个 x/y 对的类似提示对消除混淆大有帮助。考虑到以上所有因素,您的代码可以重写为:

int main (void) {

    size_t npoints, poly_id;
    size_t npolys = 0;
    size_t it = 0;
    struct Point a, b;

    printf ("\nNumber of polygons to enter: ");
    scanf (" %zu", &npolys);

    for (it = 0; it < npolys; it++)
    {
        double x[MAX_PTS], y[MAX_PTS];
        double perimeter = 0;
        double area = 0;
        size_t iter = 0;

        printf ("\nEnter npoints & poly_id    : ");
        scanf("%zu %zu", &npoints, &poly_id);

        printf ("Enter the first point X & Y: ");
        scanf("%lf %lf", &a.x, &a.y);

        x[iter] = a.x;
        y[iter] = a.y;

        struct Point initialPoint = a;

        for (iter = 1; iter < npoints; ++iter) 
        {
            printf ("           next point X & Y: ");
            scanf("%lf %lf", &b.x, &b.y);   /* input for new-point. */

            x[iter] = b.x;
            y[iter] = b.y;

            perimeter += getDistance(a, b); /* add the perimeter.   */
            a = b;                          /* new-pt is first-pt   */
        }

        /* complete polygon joining the last-point with initial-point. */
        perimeter += getDistance (b, initialPoint);
        area = polygon_area (npoints, x, y); 

        printf("\nPolygon %zu is %zu\n", it, poly_id);
        printf("perimeter = %2.2lf m\n", perimeter);
        printf("     area = %2.2lf m^2\n", area);

    }

    return 0;
}

但是为什么不为您的代码编写一个输入例程来读取您的数据文件并消除容易出错的用户输入呢?这需要一点时间,但并不难。这样您就可以完全分离代码的输入和处理功能。

这使您可以真正专注于以逻辑方式布置代码的处理部分,而不是让处理逻辑散布用户输入。以下是一个示例,说明如何将输入与代码逻辑分开有助于保持代码的清洁和可读性。它在开始第一次计算之前将所有数据读入结构数组中。

当您将代码分离为逻辑函数时,它使维护任何单独的计算(如 perimeterarea)成为调整单个函数逻辑的简单问题。请查看以下内容,如果您有任何问题,请告诉我:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <math.h>

#define MAXPTS 100
#define MAXPOLYS 100

typedef struct point {
    double x, y;
} point;

typedef struct polygon {
    size_t sz;
    size_t id;
    point *vertex;
} polygon;

double get_distance (point a, point b);
double poly_perim (polygon a);
double polygon_area (polygon pg);
polygon *read_data (char *fn);

int main (int argc, char **argv)
{
    if (argc < 2 ) {
        fprintf (stderr, "error: insufficient input, usage: %s filename\n", argv[0]);
        return 1;
    }

    size_t it = 0;
    size_t idx = 0;
    polygon *pg = read_data (argv[1]);

    if (!pg) return 1;

    while (pg[idx].sz)
    {
        printf ("\n id: %zu   points: %zu  perimeter: %6.2lf  area: %6.2lf\n\n", 
                pg[idx].id, pg[idx].sz, poly_perim (pg[idx]), polygon_area (pg[idx]));

        for (it = 0; it < pg[idx].sz; it++)
            printf ("  %5.2lf  %5.2lf\n", pg[idx].vertex[it].x, pg[idx].vertex[it].y);

        idx++;
    }

    return 0;
}

double get_distance (point a, point b)
{
    double distance;
    distance = sqrt ((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
    return distance;
}

double poly_perim (polygon a)
{
    int i = 0;
    double perim = get_distance (a.vertex[0], a.vertex[a.sz -1]);

    for (i = 1; i < a.sz; i++)
        perim += get_distance (a.vertex[i-1], a.vertex[i]);

    return perim;
}

double polygon_area (polygon pg)
{
    double area = 0.0;
    int i = 0;

    for (i = 0; i < pg.sz; ++i) 
    {
        int j = (i + 1) % pg.sz;
        area += (pg.vertex[i].x * pg.vertex[j].y - pg.vertex[j].x * pg.vertex[i].y);
    }

    area /= 2.0;
    area = area > 0 ? area : -1 * area;

    return area;
}

polygon *read_data (char *fn)
{
    char *ln = NULL;
    size_t n = 0;
    size_t it = 0;
    size_t idx = 0;
    ssize_t nchr = 0;
    FILE *fp = NULL;
    polygon *pg = NULL;

    if (!(fp = fopen (fn, "r"))) {
        fprintf (stderr, "%s() error: file open failed '%s'.\n", __func__, fn);
        exit (EXIT_FAILURE);
    }

    if (!(pg = calloc (MAXPOLYS, sizeof *pg))) {
        fprintf (stderr, "%s() error: virtual memory allocation failed.\n", __func__);
        exit (EXIT_FAILURE);
    }

    while ((nchr = getline (&ln, &n, fp)) != -1)
    {
        char *p = ln;
        char *ep = NULL;
        long lnum = 0;
        double dnum = 0;

        errno = 0;
        lnum = strtol (p, &ep, 10);
        if (errno == 0 && (p != ep && lnum != 0))
            pg[idx].sz = (size_t)lnum;
        else {
            fprintf (stderr, "%s() error: file read failure '%s'.\n", __func__, fn);
            exit (EXIT_FAILURE);
        }

        p = ep;
        errno = 0;
        lnum = strtol (p, &ep, 10);
        if (errno == 0 && (p != ep && lnum != 0))
            pg[idx].id = (size_t)lnum;
        else {
            fprintf (stderr, "%s() error: file read failure '%s'.\n", __func__, fn);
            exit (EXIT_FAILURE);
        }

        pg[idx].vertex = calloc (pg[idx].sz, sizeof *(pg[idx].vertex));
        if (!pg[idx].vertex) {
            fprintf (stderr, "%s() error: virtual memory allocation failed.\n", __func__);
            exit (EXIT_FAILURE);
        }

        for (it = 0; it < pg[idx].sz; it++)
        {
            p = ep;
            errno = 0;
            dnum = strtod (p, &ep);
            if (errno == 0 && (p != ep && lnum != 0))
                pg[idx].vertex[it].x = dnum;
            else {
                fprintf (stderr, "%s() error: file read failure '%s'.\n", __func__, fn);
                exit (EXIT_FAILURE);
            }

            p = ep;
            errno = 0;
            dnum = strtod (p, &ep);
            if (errno == 0 && (p != ep && lnum != 0))
                pg[idx].vertex[it].y = dnum;
            else {
                fprintf (stderr, "%s() error: file read failure '%s'.\n", __func__, fn);
                exit (EXIT_FAILURE);
            }
        }
        idx++;
        if (idx == MAXPOLYS) {
            fprintf (stderr, "%s() warning: MAXPOLYS reached in file '%s'.\n", __func__, fn);
            break;
        }
    }

    fclose (fp);
    if (ln) free (ln);

    return pg;
}

输入

$ cat dat/poly.txt
  3  12867  1.0 2.0  1.0 5.0  4.0 5.0
  5  15643  1.0 2.0  4.0 5.0  7.8 3.5  5.0 0.4  1.0 0.4

输出

$ ./bin/poly dat/poly.txt

 id: 12867   points: 3  perimeter:  10.24  area:   4.50

   1.00   2.00
   1.00   5.00
   4.00   5.00

 id: 15643   points: 5  perimeter:  18.11  area:  19.59

   1.00   2.00
   4.00   5.00
   7.80   3.50
   5.00   0.40
   1.00   0.40

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-06-28
    • 1970-01-01
    • 2019-12-04
    • 1970-01-01
    • 1970-01-01
    • 2018-08-23
    • 1970-01-01
    相关资源
    最近更新 更多