c - Issue with program output -
below program determines perimeter , area of polygon given amount of (x,y) coordinates seem getting wrong output , can't see why.
the input is:
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
with first entry being number of points (points) , second entry being polygon id, after set of coordinates.
#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; (int = 0; < 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; // start 0 value of parameter. (iteration = 1; iteration < npoints; ++iteration) { scanf("%lf %lf", &b.x, &b.y); // take input new-point. perimeter += getdistance(a, b); // add perimeter. // next iteration, new-point first-point in getdistance = b; } // complete polygon last-edge joining last-point // initial-point. perimeter += getdistance(a, initialpoint); printf("first polygon %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; (iteration = 0; iteration < npoints; ++iteration) { scanf("%lf %lf", &(x[iteration]), &(y[iteration])); } area = polygon_area(npoints, x, y); printf("first polygon %d\n", poly_id); printf("area = %2.2lf m^2\n", area); } else if(scanf("%d", &npoints)==0) { exit(exit_success); } return 0; }
my output keep getting is:
first polygon 12867 perimeter = 10.24 m first polygon 15643 area = 19.59 m^2
but output want is:
first polygon 12867 perimeter = 10.24 m first polygon 12867 area = 4.50 m^2
or alternatively:
first polygon 12867 perimeter = 10.24 m area = 4.50 m^2
would appreciated if point out i've gone wrong.
if haven't sorted out yet, problem obvious. read data first polygon , calculate perimeter
:
perimeter += getdistance(a, initialpoint); printf("first polygon %d\n", poly_id); printf("perimeter = %2.2lf m\n", perimeter);
then, inexplicably, read data second polygon before calculating area:
scanf("%d %d", &npoints, &poly_id); double x[max_pts], y[max_pts]; double area = 0; <snip> area = polygon_area(npoints, x, y);
how expect area first polygon using data second polygon bit bewildering.
what need calculate both perimeter
, area
each polygon before reading data next. rather if
block of code, prompt enter number of polygons
process , like:
for (i = 0; < npolys; i++) { <read data poly> <calculate perimeter> <calculate area> <display results> }
next, when expect data user, prompt it. don't leave user looking @ blinking cursor wondering if program hung, etc.. simple printf
asking number of points , polygon id works fine. prompt enter each x/y pair goes long way eliminating confusion. taking above consideration, code re-written as:
int main (void) { size_t npoints, poly_id; size_t npolys = 0; size_t = 0; struct point a, b; printf ("\nnumber of polygons enter: "); scanf (" %zu", &npolys); (it = 0; < 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 first point x & y: "); scanf("%lf %lf", &a.x, &a.y); x[iter] = a.x; y[iter] = a.y; struct point initialpoint = a; (iter = 1; iter < npoints; ++iter) { printf (" next point x & y: "); scanf("%lf %lf", &b.x, &b.y); /* input new-point. */ x[iter] = b.x; y[iter] = b.y; perimeter += getdistance(a, b); /* add perimeter. */ = b; /* new-pt first-pt */ } /* complete polygon joining last-point initial-point. */ perimeter += getdistance (b, initialpoint); area = polygon_area (npoints, x, y); printf("\npolygon %zu %zu\n", it, poly_id); printf("perimeter = %2.2lf m\n", perimeter); printf(" area = %2.2lf m^2\n", area); } return 0; }
but why not write input routine code read data file , eliminate error prone user input? takes little time, it's not hard. way can separate input , processing functions of code.
that frees concentrate on laying processing part of code out in logical manner, instead of having processing logic sprinkled user input. following example of how separating input logic of code can keep code clean , readable. reads data array of structures before beginning first computation.
when keep code separated logical function, makes maintaining individual computation perimeter
or area
simple matter of adjusting logic of single function. take @ following , let me know if have questions:
#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 = 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])); (it = 0; < 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 = 0; double perim = get_distance (a.vertex[0], a.vertex[a.sz -1]); (i = 1; < 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 = 0; (i = 0; < 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 = 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); } (it = 0; < 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; }
input
$ 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
output
$ ./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