Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 2 years ago.
Improve this question
I have to develop these 4 functions:
double distance (const point_t * a, const point_t * b)
double perimeter (const polygon_t * poly)
polygon_t create_triangle (point_t p0, double base, double height)
polygon_t create_square (point_t p0, double side)
The rest of the body of the program was already defined, but I can't figure out how to develop the last two functions, I would need someone to point me in the correct way.
My idea was to initialize the vector to then be able to make the square and the triangle from this but I have a difficulty in developing the function.
Can you help me?
P.S. I leave you below the delivery of the exercise and what I wrote myself:
"The program represents polygons of any number of sides using dynamic arrays of points. Triangles and squares, as notable polygons, can be conveniently constructed using the create_triangle() and create_square() shortcuts.
To construct other polygons it is necessary to manually populate the struct polygon_t through the appropriate assignments.
The main () constructs a triangle and a square and calculates the perimeter by calling the perimeter () function. The types polygon_t and point_t and the print_polygon () function are already implemented, they are located at the top of the source and are not editable.
Implement the following functions so that main() compiles and the program is complete:
the function polygon_t create_triangle (point_t p0, double base, double height) so that it returns by value a structure of type polygon_t suitably populated with the points that form an isosceles triangle having point of origin (bottom left point) in p0, base base length and height length height;
the function polygon_t create_square (point_t p0, double side) so that it returns by value a structure of the polygon_t type suitably populated with the points that form a square having a point of origin (bottom left point) in p0, and side length side ;
the function double perimeter (const polygon_t * poly) so that it calculates the perimeter of the polygon passed as an argument: use the distance() function between all the pairs of contiguous points and calculate the sum of the sides;
do not make assumptions about the number of sides: the data structure can represent any polygons;
the function double distance (const point_t * a, const point_t * b) which calculates the Euclidean distance between the two data points.
Example: the following program constructs a square with side 2 and a triangle with base 1 and height 0.86602; then calculate the perimeter of both."
#include <assert.h>
#include <ctype.h>
#include <limits.h>
#include <math.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
char* readline();
char* ltrim(char*);
char* rtrim(char*);
double parse_double(char*);
typedef struct {
double x, y;
} point_t;
typedef struct {
size_t len;
point_t* points;
} polygon_t;
void print_polygon(const polygon_t* poly) {
size_t i;
printf("polygon_t(%ld)[", poly->len);
for (i = 0; i < poly->len; ++i) {
printf("(%g, %g) ", poly->points[i].x, poly->points[i].y);
}
printf("\b]");
}
/* da implementare */
double distance(const point_t* a, const point_t* b) {
float dist;
point_t* x = (point_t*) a;
point_t* y = (point_t*) b;
dist= sqrt((a->x - b->x) + (a->y - b->y));
return dist;
}
/* da implementare: deve usare distance() */
double perimeter(const polygon_t* poly) {
float per_tr= distance(poly->points, poly->points) + distance(poly->points, poly->points) +
distance(poly->points, poly->points);
float per_sq= distance(poly->points, poly->points) * 4;
return per_sq && per_tr;
}
/* da implementare */
polygon_t create_triangle(point_t p0, double base, double height) {
size_t i;
point_t p2;
polygon_t p1;
for (i = 0; i < p1.len; ++i)
p1.points[i].x= 0;
//base= distance(p1.points, p1.points);
//height= sqrt(pow(distance(p1.points, p1.points),2) - (pow(base,2)/4.0)) ;
p1.len[p1.points].x= 0;
return p1;
}
/* da implementare */
polygon_t create_square(point_t p0, double side) {
polygon_t p2;
size_t i;
p0.x = 0;
p0.y = 0;
for (i = 0; i < p2.len; ++i)
p2.points[i].x= 0;
}
p2.len[p2.points]= p2.points[side * 4,0];
// side= distance(p2.points, p2.points);
return p2;
}
int main()
{
FILE* fptr = fopen(getenv("OUTPUT_PATH"), "w");
double x = parse_double(ltrim(rtrim(readline())));
double y = parse_double(ltrim(rtrim(readline())));
double l = parse_double(ltrim(rtrim(readline())));
double b = parse_double(ltrim(rtrim(readline())));
double h = parse_double(ltrim(rtrim(readline())));
point_t origin;
polygon_t sq;
polygon_t tr;
origin.x = x; /* input riga #1 */
origin.y = y; /* input riga #2 */
sq = create_square(origin, l); /* input riga #3 */
tr = create_triangle(origin, b, h); /* input riga #4, #5 */
double p1 = perimeter(&sq);
double p2 = perimeter(&tr);
fprintf(fptr, "%.2f\n", p1); /* output riga #1 */
fprintf(fptr, "%.2f\n", p2); /* output riga #2 */
fclose(fptr);
return 0;
}
char* readline() {
size_t alloc_length = 1024;
size_t data_length = 0;
char* data = malloc(alloc_length);
while (true) {
char* cursor = data + data_length;
char* line = fgets(cursor, alloc_length - data_length, stdin);
if (!line) {
break;
}
data_length += strlen(cursor);
if (data_length < alloc_length - 1 || data[data_length - 1] == '\n') {
break;
}
alloc_length <<= 1;
data = realloc(data, alloc_length);
if (!data) {
data = '\0';
break;
}
}
if (data[data_length - 1] == '\n') {
data[data_length - 1] = '\0';
data = realloc(data, data_length);
if (!data) {
data = '\0';
}
} else {
data = realloc(data, data_length + 1);
if (!data) {
data = '\0';
} else {
data[data_length] = '\0';
}
}
return data;
}
char* ltrim(char* str) {
if (!str) {
return '\0';
}
if (!*str) {
return str;
}
while (*str != '\0' && isspace(*str)) {
str++;
}
return str;
}
char* rtrim(char* str) {
if (!str) {
return '\0';
}
if (!*str) {
return str;
}
char* end = str + strlen(str) - 1;
while (end >= str && isspace(*end)) {
end--;
}
*(end + 1) = '\0';
return str;
}
double parse_double(char* str) {
char* endptr;
double value = strtod(str, &endptr);
if (endptr == str || *endptr != '\0') {
exit(EXIT_FAILURE);
}
return value;
}
First need to fix distance:
#define pow2(a) ((a) * (a))
/* da implementare */
double distance(const point_t* a, const point_t* b) {
return sqrt(pow2(a->x - b->x) + pow2(a->y - b->y));
}
For perimeter, you need distance between all points and between last and first:
/* da implementare: deve usare distance() */
double perimeter(const polygon_t* poly) {
double res = 0;
for (int i = 0; i < poly->len - 1; i++) {
res += distance(&poly->points[i], &poly->points[i+1]);
}
res += distance(&poly->points[poly->len - 1], &poly->points[0]);
return res;
}
Then you need to malloc points array to store some point_t
For triangle:
|\
| \
h| \
|___\
p0 base
/* da implementare */
polygon_t create_triangle(point_t p0, double base, double height) {
polygon_t p;
p.len = 3;
p.points = malloc(3 * sizeof(point_t));
p.points[0] = p0;
p.points[1].x = p0.x + base;
p.points[1].y = p0.y;
p.points[2].x = p0.x;
p.points[2].y = p0.y + height;
return p;
}
For square
+------+
| |
| |
+------+
p0
/* da implementare */
polygon_t create_square(point_t p0, double side) {
polygon_t p;
p.len = 4;
p.points = malloc(4 * sizeof(point_t));
p.points[0] = p0;
p.points[1].x = p0.x;
p.points[1].y = p0.y + side;
p.points[2].x = p0.x + side;
p.points[2].y = p0.y + side;
p.points[3].x = p0.x + side;
p.points[3].y = p0.y;
return p;
}
You need to free p.points
Incorrect algorithms aside, the syntax of your implementation will not compile. All of the issues below can be identified in your compile output if it is set to show all warnings. Regardless of that, some of the mistakes result in errors, and failure to compile.
Issue 1 - uninitialized variables:
size_t i;
point_t p2;
polygon_t p1;
for (i = 0; i < p1.len; ++i)
^^^^^^ uninitialized
p1.len is not initialized at time of first use. It can be any value at run-time possibly invoking undefined behavior
And there are more potentially uninitialized variables :
Build Status (so.prj - Debug)
s0_15.c - 9 warnings
60, 20 warning: variable 'p1.len' may be ***uninitialized***when used here
57, 4 note: variable 'p1' is declared here
61, 7 warning: variable 'p1.points' may be ***uninitialized***when used here
57, 4 note: variable 'p1' is declared here
64, 14 warning: variable 'p1.points' may be ***uninitialized***when used here
57, 4 note: variable 'p1' is declared here
77, 21 warning: variable 'p2.len' may be ***uninitialized***when used here
72, 5 note: variable 'p2' is declared here
79, 8 warning: variable 'p2.points' may be ***uninitialized***when used here
72, 5 note: variable 'p2' is declared here
83, 24 warning: variable 'p2' may be ******uninitialized****** when used here
72, 5 note: variable 'p2' is declared here
Note: actual locations will vary in your output.
Issue 2 - missing curly brace and out of scope object:
polygon_t create_square(point_t p0, double side) {
polygon_t p2;//has block scope!
size_t i;
p0.x = 0;
p0.y = 0;
for (i = 0; i < p2.len; ++i)
p2.points[i].x= 0;
}
p2.len[p2.points]= p2.points[side * 4,0];
p2 is not defined here, only within {...} above.
It is because this statement:
for (i = 0; i < p2.len; ++i)
p2.points[i].x= 0;
}
Is missing a opening curly brace {
for (i = 0; i < p2.len; ++i)
{//add this curly
p2.points[i].x= 0;
}
Related
I program in C and I am testing my program and I don't understand why I get the error -1073741819 (0xC0000005). Here is the Code:
#include <stdio.h>
#include <stdlib.h>
double interpol(double x0, double y0, double x1, double y1, double h) {
double ergebnis = (y1 - y0) / (x1 - x0) * h;
printf("%.2f\n", ergebnis);
return ergebnis;
}
void interpol_array(double *x_org, double *y_org, int dim_org,
double *x_int, double *y_int, int dim_int,
int n) {
int j, i;
double h;
i = 0;
y_org[0] = y_int[0];
for (j = 1; j < dim_int; j++) {
if (j % (n + 1) == 0 && j != 0) {
i++;
x_int[j] = x_org[i];
y_int[j] = x_org[i];
continue;
}
printf("%.2f ", y_org[0]);
}
}
int main() {
/* Pointer erzeugen auf null setzen */
double *xArrayOriginal = NULL;
double *yArrayOriginal = NULL;
double *xArrayInterpol = NULL;
double *yArrayInterpol = NULL;
/**/
int dimOriginal = 2;
int n = 3;
int dimInterpol = (n + 1) * (dimOriginal + 1) - n; /*+1 wegen der null*/
int i, j;
double h;
/* Array für die Originalwerte erzeugen */
xArrayOriginal = (double *)malloc(dimOriginal * sizeof(double));
yArrayOriginal = (double *)malloc(dimOriginal * sizeof(double));
/*Array für das Interpolierte Array erzeugen*/
xArrayInterpol = (double *)malloc(dimInterpol * sizeof(double));
yArrayInterpol = (double *)malloc(dimInterpol * sizeof(double));
xArrayOriginal[0] = 0;
xArrayOriginal[1] = 1;
xArrayOriginal[2] = 2;
yArrayOriginal[0] = 2;
yArrayOriginal[1] = 4;
yArrayOriginal[2] = 8;
interpol_array(xArrayOriginal, yArrayOriginal, dimOriginal, xArrayInterpol,
yArrayInterpol, dimInterpol, n);
return 0;
}
In my program I have 4 dynamic arrays. 2 dynamic arrays for origin x and y values and 2 dynamic arrays for interpolated x and y values. I don't program the full interpolation because I got an error. Therefore I searched the error and found out that when I use
printf("%.2f ", y_org[0]);
I get the error that you can see above. Only when I change it to
printf("test");
it works fine. So why do I get this error. what is wrong with my array list?
In the function main, the lines
int dimOriginal = 2;
...
xArrayOriginal =(double *)malloc(dimOriginal*sizeof(double));
yArrayOriginal =(double *)malloc(dimOriginal*sizeof(double));
allocate arrays for 2 double elements each. However, the lines
xArrayOriginal[2] =2;
...
yArrayOriginal[2] =8;
write out of bounds of these arrays, as the only valid elements numbers are 0 and 1. This causes undefined behavior.
Also, in the function interpol_array, the following line causes undefined behavior:
y_org[0] = y_int[0];
This is because y_int has been assigned the value of yArrayInterpol in main, but the contents of yArrayInterpol has not been initialized.
Goal: I am trying to create a ray tracer in C. I just added in a light source that should give each of my three spheres a shading effect based on where the light is. If the light is to the left of all of them, a shadow should be cased on the right.
Problem: When changing the light intensities and position of the light, all the spheres are changed uniformly. The spheres will be more or less lit equally and there is no variation of lighting on individual pixels on the sphere.
My debugging attempts: I have tried looking through the variable outputs by printing out a lot of different info and I think the source comes from my variable
diffuse_light_intensity
which does not change much (through all the iterations on the screen the value changes twice when it should be changing quite often due to the angles of the light on the surface changing quite a bit)
My Code: (my theory is the problem lies in scene_intersect() or cast_ray())
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>
#include <limits.h>
typedef struct {
float position[3];
float intensity;
} Light;
typedef struct {
float diffuse_color[3];
} Material;
typedef struct {
float center[3];
float radius;
Material material;
} Sphere;
int arrSub(const float arr1[], const float arr2[], float subArr[], int length) {
/*
Requires 3 equally sized arrays (denoted as length),
arr1 - arr2 will result in the third array subArr
*/
for (int i = 0; i < length; i++) {
subArr[i] = arr1[i] - arr2[i];
}
return 0;
}
int arrAdd(const float arr1[], const float arr2[], float addArr[], int length) {
/*
Requires 3 equally sized arrays (denoted as length),
arr1 + arr2 will result in the third array subArr
*/
for (int i = 0; i < length; i++) {
addArr[i] = arr1[i] + arr2[i];
}
return 0;
}
int arrScalarMult(const float arr1[], float scalar, float newArr[], int length) {
/*
Requires 3 equally sized arrays (denoted as length),
arr1 - arr2 will result in the third array subArr
*/
for (int i = 0; i < length; i++) {
newArr[i] = arr1[i] * scalar;
}
return 0;
}
float dotProduct(const float arr1[], const float arr2[], int length) {
/*
Returns the dot product of two equal sized arrays
(treated as vectors)
a (dot) b = a1b1 + a2b2 + ... anbn
*/
float result = 0;
for (int i = 0; i < length; i++) {
result += arr1[i] * arr2[i];
}
return result;
}
int normalize(float arr[], int len) {
//Normalize a vector (array)
float sumSqr;
float norm;
for (int i = 0; i < len; i++) {
sumSqr += arr[i] * arr[i];
}
norm = sqrt(sumSqr);
for (int i = 0; i < len; i++) {
arr[i] = arr[i] / norm;
}
return 0;
}
bool ray_intersect(const float origin[], const float dir[], float t0, Sphere s) {
/*
Ray-Sphere Intersection
Vectors:
origin (the zero vector)
dir (direction vector)
L (vector from origin to center of sphere)
Scalars:
tca
d2
thc
t0
t1
*/
float L[3] = {0,0,0}; //The zero vector
arrSub(s.center, origin, L, 3); //L is now the vector from origin to the sphere's center
float tca = dotProduct(L, dir, 3); //Projection of L onto dir
float d2 = dotProduct(L, L, 3) - tca*tca;
if (d2 > s.radius * s.radius) return false; //There is no intersection, so return false.
float thc = sqrtf((s.radius*s.radius - d2));
t0 = tca - thc;
float t1 = tca + thc;
if (t0 < 0) {
t0 = t1;
}
if (t0 < 0) return false;
return true;
}
bool scene_intersect(const float origin[], const float dir[], const Sphere s[], int len, float hit[], float N[], Material * ptr_m) {
float sphere_dist = INT_MAX;
for (size_t i=0; i < len; i++) {
float dist_i;
if (ray_intersect(origin, dir, dist_i, s[i]) && dist_i < sphere_dist) {
sphere_dist = dist_i;
float dirDist[3];
arrScalarMult(dir, dist_i, dirDist, 3);
arrAdd(origin, dirDist, hit, 3);
float hitMinusCenter[3];
arrSub(hit, s[i].center, hitMinusCenter, 3);
normalize(hitMinusCenter, 3);
N[0] = hitMinusCenter[0];
N[1] = hitMinusCenter[1];
N[2] = hitMinusCenter[2];
* ptr_m = s[i].material;
}
}
return sphere_dist<1000;
}
int cast_ray(const float origin[], const float dir[], const Sphere s[], const Light l[], int l_size, unsigned char colorArr[]) {
float point[3], N[3];
Material m;
Material * ptr_m = &m;
if (!scene_intersect(origin, dir, s, 3, point, N, ptr_m)) {
//background
colorArr[0] = 5; //red
colorArr[1] = 100; //green
colorArr[2] = 250; //blue
} else {
float diffuse_light_intensity = 0;
float light_dir[3];
for (size_t i = 0; i < l_size; i++) {
arrSub(l[i].position, point, light_dir, 3);
normalize(light_dir, 3);
diffuse_light_intensity += l[i].intensity * ((0.f >= dotProduct(light_dir, N, 3) ? (0.f) : (dotProduct(light_dir, N, 3))));
}
//light up pixel
colorArr[0] = m.diffuse_color[0] * diffuse_light_intensity;
colorArr[1] = m.diffuse_color[1] * diffuse_light_intensity;
colorArr[2] = m.diffuse_color[2] * diffuse_light_intensity;
}
return 0;
}
int render(const Sphere s[], const Light l[], int l_length) {
/*
Creates image in a new color each step.
*/
const int width = 1024;
const int height = 768;
FILE *fp = fopen("fourth.ppm", "wb"); // Write in binary mode
(void) fprintf(fp, "P6\n%d %d\n255\n", width, height);
float fov = 3.1415926535/2.; // Field of View
#pragma omp parallel for
for (size_t j = 0; j < height; j++) {
for (size_t i = 0; i < width; i++) {
float x = (2*(i+.5)/(float)width - 1)*tan(fov/2.)*width/(float)height;
float y = -(2*(j+.5)/(float)height - 1)*tan(fov/2.);
float dir[] = {x,y,-1};
normalize(dir, 3);
unsigned char color[3];
const float origin[] = {0,0,0};
cast_ray(origin, dir, s, l, l_length, color);
(void) fwrite(color, 1, 3, fp);
}
}
(void) fclose(fp);
return 0;
}
int main(void) {
Material red = {255,0,0};
Material pink = {150,10,150};
Material gold = {255, 195, 0};
//Populate with spheres
Sphere s[3];
Sphere originalS = {{-3,0,-16},2,gold};
Sphere bigS = {{-1.0, -1.5, -12}, 3, red};
Sphere anotherS = {{7,5,-18},2,pink};
s[0] = originalS;
s[1] = bigS;
s[2] = anotherS;
//Add light source
Light l[1];
Light test_light = {{-20,20,20}, 1.5};
l[0] = test_light;
render(s,l, 1);
printf("Run success!\n");
return 0;
}
If any clarification is needed on my code please let me know, I am quite new to both C and stackoverflow.
There's a fundamental error in ray_intersect where you're passing the t0 variable by value, and not as a pointer, and therefore in the scene_intersect function its value is always zero.
The other problem is that you don't initialize the sumSqr in the normalize function, resulting in that function returning NaN for each vector component.
With those two fixed I get something approximating shaded balls. The errors in that image are caused by failing to ensure that your output pixel values fall in the range [0, 255].
NB: both of these first errors are detected if you turn on full compiler error checking, warning you of uninitialised variables being used.
I'm having trouble calculating integrals for the centre of mass of a torus, which should return (2.4076, 0.16210, 0.0).
The program works for an estimation of pi/4 however I think there is an issue when I try to overwrite existing points using the setRandomDomain() function.
Here is my code:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#define DIM 1000000
double random_double() {
static const int a = 16807;
static const int c = 0;
static const long long m = 2147483647;
static long long seed = 1;
seed = (a * seed + c) % m;
return ((double) seed) / m;
}
typedef struct Domain_t {
double *x;
double *y;
double *z;
} Domain;
void constructDomain(Domain (**p_domain)) {
*p_domain = malloc(sizeof(Domain));
if(p_domain == NULL) {
printf("ERROR: Memory allocation failed\n");
}
(*p_domain)->x = malloc(DIM * sizeof(double));
if ((*p_domain)->x == NULL) {
printf("ERROR: Memory allocation failed\n");
}
(*p_domain)->y = malloc(DIM * sizeof(double));
if ((*p_domain)->y == NULL) {
printf("ERROR: Memory allocation failed\n");
}
(*p_domain)->z = malloc(DIM * sizeof(double));
if((*p_domain)->z == NULL) {
printf("ERROR: Memory allocation failed\n");
}
}
void delDomain (Domain (**p_domain)) {
if (p_domain != NULL) {
free ((*p_domain)->z);
free ((*p_domain)->y);
free ((*p_domain)->x);
free (*p_domain);
}
}
double radiusFunc(double point_x, double point_y) {
return sqrt(pow(point_x,2)+pow(point_y,2));
}
double G(double point_x, double point_y, double point_z, int R) {
return pow(point_z,2)+pow(radiusFunc(point_x,point_y)-(double)R,2);
}
typedef struct Volume_t {
int R;
int r;
int lower_x;
int upper_x;
int lower_y;
int upper_y;
int lower_z;
int upper_z;
int V;
} Volume;
void setVolume(Volume (*p_volume), int R, int r, int x1, int x2, int y1, int y2, int z1, int z2) {
p_volume->R = R;
p_volume->r = r;
p_volume->lower_x = x1;
p_volume->upper_x = x2;
p_volume->lower_y = y1;
p_volume->upper_y = y2;
p_volume->lower_z = z1;
p_volume->upper_z = z2;
if(z1 == 0 && z2 == 0)
p_volume->V = (x2-x1)*(y2-y1);
else if(y1 == 0 && y2 == 0)
p_volume->V = (x2-x1)*(z2-z1);
else if(x1 == 0 && x2 == 0)
p_volume->V = (y2-y1)*(z2-z1);
else
p_volume->V = (x2-x1)*(y2-y1)*(z2-z1);
}
void setInitialDomain(Domain (**p_domain)) {
int i;
for(i=0;i<DIM;i++) {
(*p_domain)->x[i] = random_double();
(*p_domain)->y[i] = random_double();
(*p_domain)->z[i] = random_double();
}
}
void setRandomDomain(Domain (*p_domain), Domain (**p_new_domain), Volume (*p_volume)) {
int i;
for(i=0;i<DIM;i++) {
(*p_new_domain)->x[i] = p_domain->x[i]*(double)(p_volume->upper_x - p_volume->lower_x) + (double)p_volume->lower_x;
(*p_new_domain)->y[i] = p_domain->y[i]*(double)(p_volume->upper_y - p_volume->lower_y) + (double)p_volume->lower_y;
(*p_new_domain)->z[i] = p_domain->z[i]*(double)(p_volume->upper_z - p_volume->lower_z) + (double)p_volume->lower_z;
}
}
double setIntegrand(Domain (*p_domain), char c) {
double *p_x = p_domain->x;
double *p_y = p_domain->y;
double *p_z = p_domain->z;
if(c=='x')
return *p_x;
else if(c=='y')
return *p_y;
else if(c=='z')
return *p_z;
else
return 1.;
}
double calculateIntegral(Domain (*p_domain), Volume (*p_volume), char c) {
int i;
double F = 0.;
for(i=0;i<DIM;i++) {
if(G(p_domain->x[i], p_domain->y[i], p_domain->z[i], p_volume->R)<=(double)p_volume->r) {
F += setIntegrand(p_domain, c);
}
}
return F*(double)p_volume->V/(double)DIM;
}
int main() {
Domain *p_initial_domain;
Domain *p_random_domain;
constructDomain(&p_initial_domain);
printf("Point 1: successful\n");
constructDomain(&p_random_domain);
printf("Point 2: successful\n");
setInitialDomain(&p_initial_domain);
Volume circle, *p_circle;
p_circle = &circle;
setVolume(p_circle,0,1,0,1,0,1,0,0);
setRandomDomain(p_initial_domain, &p_random_domain, p_circle);
printf("PI/4 is approximately %f\n", calculateIntegral(p_random_domain, p_circle, 'p'));
Volume torus, *p_torus;
p_torus = &torus;
setVolume(p_torus,3,1,1,4,-3,4,-1,1);
setRandomDomain(p_initial_domain, &p_random_domain, p_torus);
double M = calculateIntegral(p_random_domain, p_torus, 'p');
double X = calculateIntegral(p_random_domain, p_torus, 'x');
double Y = calculateIntegral(p_random_domain, p_torus, 'y');
double Z = calculateIntegral(p_random_domain, p_torus, 'z');
printf("rho integral is approximately %f\n", M);
printf("x integral is approximately %f\n", X);
printf("y integral is approximately %f\n", Y);
printf("z integral is approximately %f\n", Z);
printf("Centre of mass is approximately (%f, %f, %f)\n", X/M, Y/M, Z/M);
delDomain(&p_initial_domain);
delDomain(&p_random_domain);
// return pointers??
// array of structs??
return 0;
}
Currently outputs:
PI/4 is approximately 0.785436
rho integral is approximately 22.101282
x integral is approximately 22.101801
y integral is approximately -45.953770
z integral is approximately 11.298411
Centre of mass is approximately (1.000023, -2.079235, 0.511211)
Any ideas how to solve this?
Also, please can someone explain how I would use functions returning pointers and why it may be better to create an array of structs instead of a struct of arrays?
Your problem is that you call setIntegrand in a loop over all points, but you always take the first point:
double *p_x = p_domain->x;
// ...
return *p_x;
This returns the first double in your array. Remember that *x is equivalent to x[0]. Pass the index to the function:
double setIntegrand(Domain (*p_domain), char c, int i)
{
if (c == 'x') return p_domain->x[i];
if (c == 'y') return p_domain->y[i];
if (c == 'z') return p_domain->z[i];
return 1.;
}
and then call it with that index.
for (i = 0; i < DIM; i++) {
if (G(...) <= p_volume->r) {
F += setIntegrand(p_domain, c, i);
}
}
As to your additional questions: Using an array of structs keeps the things that go together (here, the three coordinates of the points) nearby. You can also easily just pass a point to a function with a single argument.
If you have a constructor, that is a function that creates a new thing by allocating on the heap and initialising the new memory, returning a pointer is a useful idiom. (I find it more idiomatic than passing a point to a pointer, but whoever designed to fopen_s function didn't think so.)
Let's put both changes together:
typedef struct Point Point;
typedef struct Domain Domain;
struct Point {
double x;
double y;
double z;
};
struct Domain {
size_t length;
Point *point;
};
Domain *constructDomain(size_t length)
{
Domain *dom = malloc(sizeof(*dom));
if (dom) {
dom->length = length;
dom->point = calloc(length, sizeof(*dom->point));
// check success
}
return dom;
}
First note, when possible it generally best to reduce the number of heap allocations and leave variables on the stack, less room for error. I'd say if you want 1M x 3 x sizeof(double) bytes, arround 24M, it is best to dynamically allocate it on the heap. We can leave the structure that holds these on the stack.
Another thing is when you create a variable, you don't need to create another variable to point to it, just use the original variable.
Last note is commenting, I personally comment every line of code but that may be to much here. I find it helpful to write out what exactly you are trying to do with each line of code to help find bugs.
You don't need to return pointers anywhere here i don't think, perhaps when you were passing pointer to a pointer it would have been better to just return a pointer. An array of structures is another way of doing it, it means only one malloc and one free but alignment could cause extra memory to be used (padding) which could be considerable when using 1M points, there likely won't be any padding here tho because you are using double floating points. I think your arrays are fine.
I made some changes with the way you are using pointers, this likely won't solve your problem but it at least cleans things up a bit.
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#define DIM 1000000
typedef struct Domain_t {
double *x;
double *y;
double *z;
} Domain;
typedef struct Volume_t {
int R;
int r;
int lower_x;
int upper_x;
int lower_y;
int upper_y;
int lower_z;
int upper_z;
int V;
} Volume;
double random_double() {
static const int a = 16807;
static const int c = 0;
static const long long m = 2147483647;
static long long seed = 1;
seed = (a * seed + c) % m;
return ((double) seed) / m;
}
void constructDomain(Domain *p_domain) {
p_domain->x = malloc(DIM * sizeof(double));
if (p_domain->x == NULL) {
printf("ERROR: Memory allocation failed\n");
}
p_domain->y = malloc(DIM * sizeof(double));
if (p_domain->y == NULL) {
printf("ERROR: Memory allocation failed\n");
}
p_domain->z = malloc(DIM * sizeof(double));
if(p_domain->z == NULL) {
printf("ERROR: Memory allocation failed\n");
}
}
void delDomain (Domain *p_domain) {
if (p_domain != NULL) {
free (p_domain->z);
free (p_domain->y);
free (p_domain->x);
}
}
double radiusFunc(double point_x, double point_y) {
return sqrt(pow(point_x,2)+pow(point_y,2));
}
double G(double point_x, double point_y, double point_z, int R) {
return pow(point_z,2)+pow(radiusFunc(point_x,point_y)-(double)R,2);
}
void setVolume(Volume *p_volume, int R, int r, int x1, int x2, int y1, int y2, int z1, int z2) {
p_volume->R = R;
p_volume->r = r;
p_volume->lower_x = x1;
p_volume->upper_x = x2;
p_volume->lower_y = y1;
p_volume->upper_y = y2;
p_volume->lower_z = z1;
p_volume->upper_z = z2;
if(z1 == 0 && z2 == 0)
p_volume->V = (x2-x1)*(y2-y1);
else if(y1 == 0 && y2 == 0)
p_volume->V = (x2-x1)*(z2-z1);
else if(x1 == 0 && x2 == 0)
p_volume->V = (y2-y1)*(z2-z1);
else
p_volume->V = (x2-x1)*(y2-y1)*(z2-z1);
}
void setInitialDomain(Domain *p_domain) {
int i;
for(i=0;i<DIM;i++) {
p_domain->x[i] = random_double();
p_domain->y[i] = random_double();
p_domain->z[i] = random_double();
}
}
void setRandomDomain(Domain *p_domain, Domain *p_new_domain, Volume *p_volume) {
int i;
for(i=0;i<DIM;i++) {
p_new_domain->x[i] = p_domain->x[i] * (double) (p_volume->upper_x - p_volume->lower_x) + (double) p_volume->lower_x;
p_new_domain->y[i] = p_domain->y[i] * (double) (p_volume->upper_y - p_volume->lower_y) + (double) p_volume->lower_y;
p_new_domain->z[i] = p_domain->z[i] * (double) (p_volume->upper_z - p_volume->lower_z) + (double) p_volume->lower_z;
}
}
double setIntegrand(Domain (*p_domain), char c) {
double *p_x = p_domain->x;
double *p_y = p_domain->y;
double *p_z = p_domain->z;
if(c=='x')
return *p_x;
else if(c=='y')
return *p_y;
else if(c=='z')
return *p_z;
else
return 1.0;
}
double calculateIntegral(Domain *p_domain, Volume *p_volume, char c) {
int i;
double F = 0.0;
for(i=0;i<DIM;i++) {
if(G(p_domain->x[i], p_domain->y[i], p_domain->z[i], p_volume->R)<=(double)p_volume->r) {
F += setIntegrand(p_domain, c);
}
}
return F * (double) p_volume->V / (double)DIM;
}
int main() {
Domain initial_domain;
Domain random_domain;
Volume circle;
Volume torus;
/* memory allocation */
constructDomain(&initial_domain);
constructDomain(&random_domain);
/* initialization */
setInitialDomain(&initial_domain);
/* volume */
setVolume(&circle,0,1,0,1,0,1,0,0);
setRandomDomain(&initial_domain, &random_domain, &circle);
/* integral */
printf("PI/4 is approximately %f\n", calculateIntegral(&random_domain, &circle, 'p'));
setVolume(&torus,3,1,1,4,-3,4,-1,1);
setRandomDomain(&initial_domain, &random_domain, &torus);
double M = calculateIntegral(&random_domain, &torus, 'p');
double X = calculateIntegral(&random_domain, &torus, 'x');
double Y = calculateIntegral(&random_domain, &torus, 'y');
double Z = calculateIntegral(&random_domain, &torus, 'z');
printf("rho integral is approximately %f\n", M);
printf("x integral is approximately %f\n", X);
printf("y integral is approximately %f\n", Y);
printf("z integral is approximately %f\n", Z);
printf("Centre of mass is approximately (%f, %f, %f)\n", X/M, Y/M, Z/M);
delDomain(&initial_domain);
delDomain(&random_domain);
return 0;
}
I'm working on some code that initialises a couple of blocks of memory with random values. I will use these blocks of memory as matrices for the weights and biases in a neural net later on but that is not the point of this question.
I have two pieces off code (Code A & Code B) which does essentially the same thing, namely initialising a block of memory with random values. Both pieces of code compile just fine, however when I execute Code B I get a segmentation fault 11 error and the code stops executing. Code B works with a structure of variable member length and I believe this creates the problem. However i don't know how to fix this.
My question: Does someone know what the problem causes and how to fix it? I would really love to have Code B working since this is convenient in the code later on. I have pasted both pieces of code below. The system where I have this code tested is macOS.
Any help would be greatly appreciated!
Code A:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#define DEBUG
/*
Function prototypes
*/
void init_rand(float *p, int size);
int main(int argc, char const *argv[])
{
int neurons [] = {10,10,10}; // use this array to define the neuralnet
int layers = sizeof(neurons)/sizeof(int); // this calculates the amount of layers in the neuralnet (i.e. the amount of members in the array 'neurons')
// array of pointers for the memory given by malloc
float *pwl[layers];
float *pbl[layers];
float *pzl[layers];
float *pal[layers];
for (int i = 1; i < layers; i++) // create memory for the matrices and assign the start adress of each matrix to the pointers
{
pwl[i] = (float *)malloc(neurons[i]*neurons[(i-1)]*sizeof(float));
pbl[i] = (float *)malloc(neurons[i]*sizeof(float));
pzl[i] = (float *)malloc(neurons[i]*sizeof(float));
pal[i] = (float *)malloc(neurons[i]*sizeof(float));
}
for (int i = 1; i < layers; i++) // initialize the weights and the biases with random values
{
init_rand(pwl[i], neurons[i]*neurons[i-1]);
init_rand(pbl[i], neurons[i]);
}
return 0;
}
/*
Random generator with a gaussian distribution. Mean = 0, Variance = 1
*/
double gaussrand()
{
static double V1, V2, S;
static int phase = 0;
double X;
if(phase == 0)
{
do
{
double U1 = (double)rand() / RAND_MAX;
double U2 = (double)rand() / RAND_MAX;
V1 = 2 * U1 - 1;
V2 = 2 * U2 - 1;
S = V1 * V1 + V2 * V2;
} while(S >= 1 || S == 0);
X = V1 * sqrt(-2 * log(S) / S);
} else
X = V2 * sqrt(-2 * log(S) / S);
phase = 1 - phase;
return X;
}
/*
This function initializes a float array with random gaussian distributed numbers
*/
void init_rand(float *p, int size)
{
for (int i = 0; i < size; i++, p++)
{
*p = (float)gaussrand();
#ifdef DEBUG
printf("%d:*p = %f\n", i, *p); //
#endif
}
}
Code B:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#define DEBUG
struct neuralnet
{
int struct_size;
float *pwl[0];
float *pbl[0];
float *pzl[0];
float *pal[0];
};
/*
Function prototypes
*/
void init_rand(float *p, int size);
struct neuralnet* create_neuralnet(struct neuralnet* pnet, int layers);
int main(int argc, char const *argv[])
{
int neurons [] = {10,10,10}; // use this array to define the neuralnet
int layers = sizeof(neurons)/sizeof(int); // this calculates the amount of layers in the neuralnet
struct neuralnet *pnet; // create a struct neuralnet pointer
pnet = create_neuralnet(pnet, layers); // this function will create a neuralnet structure with variable size members
for (int i = 1; i < layers; i++) // create memory for the matrices and assign the start adress of each matrix to the pointers
{
pnet->pwl[i] = (float *)malloc(neurons[i]*neurons[(i-1)]*sizeof(float));
pnet->pbl[i] = (float *)malloc(neurons[i]*sizeof(float));
pnet->pzl[i] = (float *)malloc(neurons[i]*sizeof(float));
pnet->pal[i] = (float *)malloc(neurons[i]*sizeof(float));
}
for (int i = 1; i < layers; i++) // initialize the weights and the biases with random values
{
init_rand(pnet->pwl[i], neurons[i]*neurons[i-1]);
init_rand(pnet->pbl[i], neurons[i]);
}
return 0;
}
/*
Random generator with a gaussian distribution. Mean = 0, Variance = 1
*/
double gaussrand()
{
static double V1, V2, S;
static int phase = 0;
double X;
if(phase == 0)
{
do
{
double U1 = (double)rand() / RAND_MAX;
double U2 = (double)rand() / RAND_MAX;
V1 = 2 * U1 - 1;
V2 = 2 * U2 - 1;
S = V1 * V1 + V2 * V2;
} while(S >= 1 || S == 0);
X = V1 * sqrt(-2 * log(S) / S);
} else
X = V2 * sqrt(-2 * log(S) / S);
phase = 1 - phase;
return X;
}
/*
This function initializes a float array with random gaussian distributed numbers
*/
void init_rand(float *p, int size)
{
for (int i = 0; i < size; i++, p++)
{
*p = (float)gaussrand();
#ifdef DEBUG
printf("%d:*p = %f\n", i, *p); //
#endif
}
}
/*
This function creates the structure with members of variable length
*/
struct neuralnet* create_neuralnet(struct neuralnet *pnet, int layers)
{
pnet = (struct neuralnet *)malloc(sizeof(*pnet) + sizeof(float *) * layers * 4);
return pnet;
}
This question already exists:
Closed 11 years ago.
Possible Duplicate:
Is this C-program correct(pointers and arrays)?
My program crashes when I free the mallocated array in the end. Why?
Also, I'm not 100% on how to allocate it in the first place. The program works as intended though, ecept for the crash when I free the pointer.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
/* Approximates a solution to a differential equation on the form:
y'(t) + ay(t) = x(t)
y(0) = b
*/
double* runge_kutta_2nd_order(double stepSize, double a, double b, double (*x) (double), double upto)
{
int resultSize = ((int) (upto / stepSize)) + 1;
double yt = b;
double time;
double k1,k2,ystar1,ystar2;
int index = 1;
double *results = (double*) malloc(resultSize * (sizeof(double)));
if(results == NULL)
exit(0);
results[0] = b;
for(time = 0; time <= upto; time += stepSize)
{
k1 = x(time) - a * yt;
ystar1 = yt + stepSize * k1;
k2 = x(time + stepSize) - a * ystar1;
ystar2 = yt + (k1 + k2) / 2 * stepSize;
yt = ystar2;
results[index] = ystar2;
index++;
}
return results;
}
void free_results(double *r)
{
free(r);
r = NULL;
}
double insignal(double t)
{
return exp(t/2)*(sin(5*t) - 10*cos(5*t));
}
int main(void)
{
int i;
double *res = runge_kutta_2nd_order(0.01,-1,0,&insignal,10);
printf("\nRunge Kutta 2nd order approximation of the differential equation:");
printf("\ny'(t) - y(t) = e^(t/2) * (sin(5t) - 10cos(5t))");
printf("\ny(0) = 0");
printf("\n0 <= t <= 10");
for(i=0; i<1001; i++){
printf("\ni = %lf => y = ", 0.01*i);
printf("%lf", res[i]);
}
printf("\n");
free_results(res);
return 0;
}
You have a heap overflow in runge_kutta_2nd_order. Carefully check the loop to ensure that index < resultSize always holds.