Pointers to structs, C - c

I have these two structs, everything goes well, but when I try calculating poly->scope
The output is 0.0 , like nothing really happens.
Also, I get some errors I cannot understand, for example -
the line scanPoint(&poly->points[i]); says "Dereferencing NULL pointer"
Thanks for help.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef struct point
{
int x, y;
}point;
typedef struct polygon
{
int n;
point* points;
double scope;
}polygon;
void scanPoint(point*);
void scanPolygon(polygon*);
double distance(point*, point*);
void calculatePolygonScope(polygon*);
void freeMemory(polygon*);
int main()
{
polygon poly;
scanPolygon(&poly);
calculatePolygonScope(&poly);
freeMemory(&poly);
printf("Output: Scope of polygon: %.2lf\n", poly.scope);
return 0;
}
void scanPoint(point* p)
{
printf("Please Enter X of your point: \n");
scanf("%d", &p->x);
printf("Please Enter Y of your point: \n");
scanf("%d", &p->y);
}
void scanPolygon(polygon* poly)
{
int i;
printf("Please enter how many points does the polygon have? : \n");
scanf("%d", &poly->n);
poly->points = (point*)calloc(poly->n, sizeof(point));
for (i = 0; i < poly->n; i++)
{
scanPoint(&poly->points[i]);
}
}
double distance(point* p1, point* p2)
{
double x = pow(((double)p2->x - (double)p1->x), 2);
double y = pow(((double)p2->y - (double)p1->y), 2);
double dis = sqrt(x + y);
return dis;
}
void calculatePolygonScope(polygon* poly)
{
int i;
double temp = 0.0;
for (i = 0; i < poly->n-1;)
{
temp += distance(&poly->points[i], &poly->points[++i]);
}
poly->scope = temp;
}
void freeMemory(polygon* poly)
{
free(poly->points);
}

The function call distance(&poly->points[i], &poly->points[++i]); in calculatePolygonScope exhibits undefined behavior because it uses the value of i in two places, one of which modifies the value of i. From C17 6.5/2:
If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined. If there are multiple allowable orderings of the subexpressions of an expression, the behavior is undefined if such an unsequenced side effect occurs in any of the orderings.85)
85)This paragraph renders undefined statement expressions such as
i = ++i + 1;
a[i++] = i;
while allowing
i = i + 1;
a[i] = i;
To fix it, do the increment of i in the for loop control:
for (i = 0; i < poly->n-1; i++)
{
temp += distance(&poly->points[i], &poly->points[i + 1]);
}
If calculatePolygonScope is supposed to calculate the perimeter of the polygon, it is missing the edge between the first and last points. It could be changed as follows to include that edge:
void calculatePolygonScope(polygon* poly)
{
int i;
double temp = 0.0;
for (i = 0; i < poly->n-1; i++)
{
temp += distance(&poly->points[i], &poly->points[i + 1]);
}
if (poly->n > 1)
{
/* Last edge */
temp += distance(&poly->points[poly->n-1], &poly->points[0]);
}
poly->scope = temp;
}
As an aside, the distance function can be simplified by using the hypot function:
double distance(point* p1, point* p2)
{
return hypot(p2->x - p1->x, p2->y - p1->y);
}
or to avoid any possible integer overflow:
double distance(point* p1, point* p2)
{
return hypot((double)p2->x - p1->x, (double)p2->y - p1->y);
}
EDIT: OP is not allowed to use hypot, but the distance function can still be simplified by using simple multiplication to do the squaring, instead of using the more expensive (and potentially less accurate) pow function:
double distance(point* p1, point* p2)
{
double x = (double)p2->x - (double)p1->x;
double y = (double)p2->y - (double)p1->y;
double dis = sqrt(x * x + y * y);
return dis;
}
Note: It is not actually necessary to cast both operands of the subtraction operator to double. The other can be left as an int and will be converted to double automatically before the subtraction is performed.

You probably want this:
void calculatePolygonScope(polygon* poly)
{
int i;
double temp = 0.0;
for (i = 0; i < poly->n - 1; i++)
{
temp += distance(&poly->points[i], &poly->points[i + 1]);
}
poly->scope = temp;
}
With that modification the function returns the sum the polygon's segments except the last segment.
If the function is supposed to return the perimeter of the polygon, you need obviously to add another modification. I let you findout yourself how to do this as an exercise.

Related

Find the distance of the closest pair of points ( c )

#include <stdio.h>
#include <math.h>
typedef struct
{
int x,y;
}point;
double distance(point p1[], point p2[], int i)
{
double d = sqrt((pow(p2[i+1].x-p1[i].x,2)) + (pow(p2[i+1].y-p1[i].y,2)));
return d;
}
int main()
{
int size,i;
double d;
printf("Enter number of point: ");
scanf("%d",&size);
point p[size];
for(i=0;i<size;i++)
{
printf("Enter point %d: ",i+1);
scanf("%d,%d",&p[i].x,&p[i].y);
}
d = distance(p[0].x,p[0].y,0);
for(i=0;i<size-1;i++)
{
if( d > distance(p[i+1].x,p[i+1].y,i))
{
d = distance(p[i+1].x,p[i+1].y,i);
}
}
printf("Closest pair distance = %.4lf",d);
}
I have been trying to finish this homework for a while and I'm not sure on how to fix this.
The output supposed to look like this:
This is what I got:
First, I think your distance function should get two points, and not two points arrays. you also don't need to pass the index. this way your function will only do what it should do: calculate the Euclidean distance.
double distance(point p1, point p2)
{
double d = sqrt(pow(p2.x-p1.x,2) + pow(p2.y-p1.y,2));
return d;
}
Second, in your main function, do you want to check only the distance between consecutive points or between any point? I think you want the second option but decide for yourself:
first option:
for(i=0;i<size-1;i++)
{
if( d > distance(p[i],p[i+1]))
{
d = distance(p[i],p[i+1]);
}
}
second option:
for(i=0;i<size-1;i++)
{
for (j=i+1;j<size;j++)
{
if( d > distance(p[i],p[j]))
{
d = distance(p[i],p[j]);
}
}
}
notice I set j=i+1 because first, i don't want to calculate distance(p[i],p[i]) because that will always be 0 and that is the minimal value distance can return. secondly it's sufficient to test only for j>i values because distance(p[i],p[j])==distance(p[j],p[i])
I hope that cover everything
I have done some changes. Read the comments marked with // CHANGE HERE to understand the changes.
#include <stdio.h>
#include <math.h>
#include <float.h>
#include <stdlib.h>
typedef struct
{
// CHANGE HERE: double instead of int
double x, y;
} point;
// CHANGE HERE: just accept two points whose distance needs to be calculated
double distance(point p1, point p2)
{
return sqrt((pow(p1.x - p2.x, 2)) + (pow(p1.y - p2.y, 2)));
}
int main()
{
int size, i, j;
double d;
printf("Enter number of points: ");
scanf("%d", &size);
// CHANGE HERE: use malloc for variable sized arrays
point* p = malloc(size * sizeof(point));
for (i = 0; i < size; i++)
{
// CHANGE HERE: read double instead of int
printf("Enter point %d: ", i + 1);
scanf("%lf,%lf", &p[i].x, &p[i].y);
}
// CHANGE HERE: store a high value by default
d = DBL_MAX;
for (i = 0; i < size - 1; i++)
{
// CHANGE HERE: to get the exact pair of points with closest distance
// you need to compare the distance of each point with the rest
for (j = i + 1; j < size; j++)
{
// CHANGE HERE: pass previous and current point to distance
double dist = distance(p[i], p[j]);
if (d > dist)
{
d = dist;
}
}
}
printf("Closest pair distance = %.4lf", d);
// CHANGE HERE: don't forget to free malloc()ed memory
free(p);
return 0;
}
As mentioned by #tstanisl, you can also use hypot function present in math.h, like:
double distance(point p1, point p2)
{
return hypot(p1.x - p2.x, p1.y - p2.y);
}

Assigning a list within a loop

I have the following function to get the distance between some points:
#include <stdio.h>
#include <math.h>
int add_coords(size_t size, float coords[size][2])
{
float distance = 0;
for (int i=0; i < size-1; i++) {
float this[2] = coords[i]; // not allowed
float next[2] = coords[i+1];
distance = sqrt(pow(this[0] - next[0]),2) + pow(this[1] - next[1]),2));
}
return distance;
}
int main(void)
{
float coords[][2] = {{1,3}, {5,7}, {-2,-3}};
float distance = add_coords(sizeof coords / sizeof *coords, coords);
printf("The distance is %.2f\n", distance);
}
What would be the best way to do the following?
float this[2] = coords[i];
Current what I'm doing is the following, this it was a bit tricky to come up with:
// pointer to array of two
float (*this)[2], (*next)[2];
for (int i=0; i < size; i++) {
this = &coords[i];
next = &coords[i+1];
distance += sqrtf(powf((*this)[0] - (*next)[0],2) + powf((*this)[1] - *(next)[1],2));
}
I would simply use a struct, this would avoid any unwanted undefined behavior:
typedef struct coords {
float x;
float y;
} t_coords
// ...
t_coords coords = {.x= coords[i][0], .y=coords[i][1]};
Also you should be careful to declare your array coords with float f:
{{1f,3f}, {5f,7f}, {-2f,-3f}};

How to use a nested if else statements in a for loop in c

I'm having issues with my for statement. I'm trying to have a nested if else statement inside and I'm using pointers. I've tried everything and I've looked all over the internet. I've placed comments beside the lines with errors but if you see something else that's wrong please let me know. Thank you
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
void getinput(double*xptr, int*nptr)
{
int flag;
do
{
flag = TRUE;
printf("What is the value of x and the number of terms:");
scanf("%lf %i", xptr, nptr);
if (*nptr <= 0)
{
printf("The number of terms must be positive\n");
flag = FALSE;
}
}
while(flag == FALSE);
}
double sinHyper(double *xptr, int *nptr) {
int i;
double sum;
double ti;
i = 0;
ti = 0;
for (i = 0; i < *nptr; i = i+1)// I'm getting a Warning: comparioson between pointer and integer
{
if (i == 0)
{
sum = xptr;
} else {
ti = 2*i+1;
ti = ti*2*i;
ti = (xptr*xptr)/ti;// I'm getting a error: invalid operands to binary * (have 'double*' and 'double*')
sum = ti*sum;
}
}
return (sum);
}
void main() {
int n;
double x;
double sinhx;
getinput(&x, &n);
sinhx = sinHyper(&x, &n);
printf("For an x of %.0f with %i terms the sinh(x) is %f", x, n, sinhx);
return 0;
}
You forgot to dereference your pointers in several places.
The fact that this line compiles
sum = xptr;
should not mislead you: C lets you convert a pointer to a number with only a warning, while in most cases this is an error. This line should be
sum = *xptr;
It does not let you multiply pointers, so the expression where you square your pointer is an error:
(xptr*xptr)
You should either dereference the pointer twice, i.e. write
((*xptr)*(*xptr))
or make a separate variable for the current value of *xptr and use it instead:
const double x = *xptr;
ti = (x*x)/ti;
Note: This exercise should be purely theoretical, because sinHyper does not change *xptr or *nptr. Therefore, you should pass them as values, not as pointers:
double sinHyper(const double x, const int n) {
...
}
...
sinhx = sinHyper(x, n);

program.exe (C) has stopped working

I am extremely new to C and managed to compile this program, but the exe stops working upon running. I'm really not sure what's wrong.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define TINY 1.0e-20 // A small number.
void ludcmp(float a[3][3], int n, int *indx, float *d);
void lubksb(float a[3][3], int n, int *indx, float b[]) ;
int main(){
int i,n,*indx;
float *b,d;
float a[3][3] = {
{ 1.0, 2.0, 5.0},
{-1.0, 2.0, 3.0},
{ 6.0, 0.0, 1.0}
};
ludcmp(a,n,indx,&d);
lubksb(a,n,indx,b);
for(i = 1; i = 3; i++) {
printf("%.2f",b[i]);
}
getchar();
return 0;
}
For those who were asking, the 2 functions ludcmp and lubksg are below. I got them from the numerical recipes textbook, but edited some lines to remove exclusive routines which I do not have. Specifically, they are the lines with malloc, printf, and free.
The original code came with all the loops starting with 1, which is why I also started my loop with 1. I have since changed all the loops to start from 0 instead, hopefully without introducing any new errors.
You can see the original code here:
https://github.com/saulwiggin/Numerical-Recipies-in-C/tree/master/Chapter2.Solution-of-Linear-Equations
Here is ludcmp:
void ludcmp(float a[3][3], int n, int *indx, float *d)
{
int i, imax, j, k;
float big, dum, sum, temp;
float *vv; // vv stores the implicit scaling of each row.
vv = (float *) malloc(n * sizeof(float));
*d=1.0;
for (i=0;i<n;i++) {
big=0.0;
for (j=0;j<n;j++)
if ((temp=fabs(a[i][j])) > big) big=temp;
if (big == 0.0)
{
printf("Singular matrix in routine ludcmp");
//free(vv);
}
// No nonzero largest element.
vv[i] = 1.0 / big; // Save the scaling.
}
// This is the loop over columns of Crout's method.
for (j=0;j<n;j++) {
for (i=0;i<j;i++) {
sum=a[i][j];
for (k=0;k<i;k++) sum -= a[i][k]*a[k][j];
a[i][j]=sum;
}
// Initialize for the search for largest pivot element.
big=0.0;
for (i=j;i<=n;i++) {
sum=a[i][j];
for (k=0;k<j;k++)
sum -= a[i][k]*a[k][j];
a[i][j]=sum;
if ( (dum=vv[i]*fabs(sum)) >= big) {
big=dum;
imax=i;
}
}
if (j != imax) {
for (k=0;k<n;k++) {
dum=a[imax][k];
a[imax][k]=a[j][k];
a[j][k]=dum;
}
*d = -(*d);
vv[imax]=vv[j];
}
indx[j]=imax;
if (a[j][j] == 0.0) a[j][j]=TINY;
if (j != n) {
dum=1.0/(a[j][j]);
for (i=j+1;i<n;i++) a[i][j] *= dum;
}
} // Go back for the next column in the reduction.
free(vv);
}
And lubksb:
void lubksb(float a[3][3],int n,int *indx,float b[])
{
int i,ii=0,ip,j;
float sum;
for (i=1;i<=n;i++) {
ip=indx[i];
sum=b[ip];
b[ip]=b[i];
if (ii)
for (j=ii;j<=i-1;j++) sum -= a[i][j]*b[j];
else if (sum) ii=i;
b[i]=sum;
}
for (i=n;i>=1;i--) {
sum=b[i];
for (j=i+1;j<=n;j++) sum -= a[i][j]*b[j];
b[i]=sum/a[i][i];
}
}
This is a Two Dimensional Array and you are looping as it was just one. You should do something like:
for (int i = 0; i < 3; ++i) {
for(int j = 0; j < 3; ++j) {
printf("%d %d: ", i+1, j+1);
}
}
Is bad practice to define the size of the array explicit. Try to use a constant.
And as said in the comments by #Marged:
In C arrays starts in 0
b is never assigned to anything valid when it's declared:
float *b,d;
At best, it's NULL or pointing to an invalid memory address:
I don't know what the lubksb function does:
lubksb(a,n,indx,b);
But b is clearly an invalid parameter since you never assign to it before calling this function.
And with this statement:
for(i = 1; i = 3; i++) {
printf("%.2f",b[i]);
}
As others have pointed out, array indices start at zero. But there's no evidence that b has a length of three anyway.

Selecting and analysing window of points in an array

Could someone please advise me on how to resolve this problem.
I have a function which performs a simple regression analysis on a sets of point contained in an array.
I have one array (pval) which contains all the data I want to perform regression analysis on.
This is how I want to implement this.
I get an average value for the first 7 elements of the array. This is what I call a 'ref_avg' in the programme.
I want to perform a regression analysis for every five elements of the array taking the first element of this array as the 'ref_avg'. That is in every step of the regression analysis I will have 6 points in the array.
e.g
For the 1st step the ref_avg as calculated below is 70.78. So the 1st step in the simple regression will contain these points
1st = {70.78,76.26,69.17,68.68,71.49,73.08},
The second step will contain the ref_avg as the 1st element and other elements starting from the second element in the original array
2nd = {70.78,69.17,68.68,71.49,73.08,72.99},
3rd = {70.78,68.68,71.49,73.08,72.99,70.36},
4th = {70.78,71.49,73.08,72.99,70.36,57.82} and so on until the end.
The regression function is also shown below.
I don't understand why the first 3 elements of the 'calcul' array have value 0.00 on the first step of the regression, 2 elements on the 2nd step,1 elements on the 3rd.
Also the last step of the regression function is printed 3 times.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
float pval[]={76.26,69.17,68.68,71.49,73.08,72.99,70.36,57.82,58.98,69.71,70.43,77.53,80.77,70.30,70.5,70.79,75.58,76.88,80.20,77.69,80.80,70.5,85.27,75.25};
int count,Nhour;
const int MAX_HOUR = 24;
float *calcul=NULL;
float *tab_time =NULL;
float ref_avg;
int size_hour=7;
float sum=0;
int length = Nhour+1;
float m;
float b;
calcul=(float*)calloc(MAX_HOUR,sizeof(calcul));
if (calcul==NULL)
{
printf(" error in buffer\n");
exit(EXIT_FAILURE);
}
tab_time= calloc(MAX_HOUR,sizeof(float));
/* Get the average of the first seven elements */
int i;
for (i=0;i<size_hour;i++)
{
sum += pval[i];
}
ref_avg = sum / size_hour;
count=0;
/* perform the regression analysis on 5 hours increment */
while(count<=MAX_HOUR)
{
++count;
Nhour=5;
int pass = -(Nhour-1);
int i=0;
for(i=0;i<Nhour+1;i++)
{
if(count<MAX_HOUR)
{
calcul[0]=ref_avg;
calcul[i] =pval[count+pass];
pass++;
}
printf("calc=%.2f\n",calcul[i]); // For debug only
tab_time[i]=i+1;
if(i==Nhour)
{
linear_regression(tab_time, calcul, length, &m, &b);
printf("Slope= %.2f\n", m);
}
}
}
free(calcul);
calcul=NULL;
free(tab_time);
tab_time=NULL;
return 0;
}
/* end of the main function */
/* This function is used to calculate the linear
regression as it was called above in the main function.
It compiles and runs very well, was just included for the
compilation and execution of the main function above where I have a problem. */
int linear_regression(const float *x, const float *y, const int n, float *beta1, float *beta0)
{
float sumx = 0,
sumy = 0,
sumx2 = 0,
sumxy = 0;
int i;
if (n <= 1) {
*beta1 = 0;
*beta0= 0;
printf("Not enough data for regression \n");
}
else
{
float variance;
for (i = 0; i < n; i++)
{
sumx += x[i];
sumy += y[i];
sumx2 += (x[i] * x[i]);
sumxy += (x[i] * y[i]);
}
variance = (sumx2 - ((sumx * sumx) / n));
if ( variance != 0) {
*beta1 = (sumxy - ((sumx * sumy) / n)) / variance;
*beta0 = (sumy - ((*beta1) * sumx)) / n;
}
else
{
*beta1 = 0;
*beta0 = 0;
}
}
return 0;
}
I think this code produces sane answers. The reference average quoted in the question seems to be wrong. The memory allocation is not needed. The value of MAX_HOUR was 24 but there were only 23 data values in the array. The indexing in building up the array to be regressed was bogus, referencing negative indexes in the pval array (and hence leading to erroneous results). The variable Nhour was referenced before it was initialized; the variable length was not correctly set. There wasn't good diagnostic printing.
The body of main() here is substantially rewritten; the editing on linear_regression() is much more nearly minimal. The code is more consistently laid out and white space has been used to make it easier to read. This version terminates the regression when there is no longer enough data left to fill the array with 5 values - it is not clear what the intended termination condition was.
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void linear_regression(const float *x, const float *y, const int n,
float *beta1, float *beta0);
int main(void)
{
float pval[]={
76.26, 68.68, 71.49, 73.08, 72.99, 70.36, 57.82, 58.98,
69.71, 70.43, 77.53, 80.77, 70.30, 70.50, 70.79, 75.58,
76.88, 80.20, 77.69, 80.80, 70.50, 85.27, 75.25,
};
const int Nhour = 5;
const int MAX_HOUR = sizeof(pval)/sizeof(pval[0]);
const int size_hour = 7;
float ref_avg;
float sum = 0.0;
float m;
float b;
float calc_y[6];
float calc_x[6];
/* Get the average of the first seven elements */
for (int i = 0; i < size_hour; i++)
sum += pval[i];
ref_avg = sum / size_hour;
printf("ref avg = %5.2f\n", ref_avg); // JL
/* perform the regression analysis on 5 hours increment */
for (int pass = 0; pass <= MAX_HOUR - Nhour; pass++) // JL
{
calc_y[0] = ref_avg;
calc_x[0] = pass + 1;
printf("pass %d\ncalc_y[0] = %5.2f, calc_x[0] = %5.2f\n",
pass, calc_y[0], calc_x[0]);
for (int i = 1; i <= Nhour; i++)
{
int n = pass + i - 1;
calc_y[i] = pval[n];
calc_x[i] = pass + i + 1;
printf("calc_y[%d] = %5.2f, calc_x[%d] = %5.2f, n = %2d\n",
i, calc_y[i], i, calc_x[i], n);
}
linear_regression(calc_x, calc_y, Nhour+1, &m, &b);
printf("Slope= %5.2f, intercept = %5.2f\n", m, b);
}
return 0;
}
void linear_regression(const float *x, const float *y, const int n, float *beta1, float *beta0)
{
float sumx1 = 0.0;
float sumy1 = 0.0;
float sumx2 = 0.0;
float sumxy = 0.0;
assert(n > 1);
for (int i = 0; i < n; i++)
{
sumx1 += x[i];
sumy1 += y[i];
sumx2 += (x[i] * x[i]);
sumxy += (x[i] * y[i]);
}
float variance = (sumx2 - ((sumx1 * sumx1) / n));
if (variance != 0.0)
{
*beta1 = (sumxy - ((sumx1 * sumy1) / n)) / variance;
*beta0 = (sumy1 - ((*beta1) * sumx1)) / n;
}
else
{
*beta1 = 0.0;
*beta0 = 0.0;
}
}

Resources