I've written some code in regard to a uni assignment, but I keep stumbling across the problem where my custom function doesn't give any other output then zero.
Basically, I'm asking how to retrieve the result of the function to use in my code.
Here I will paste my code.
#include <stdio.h>
//math.h is included via the header file because the compiler liked it better.
int V;
int H;
int R;
int result;
#include "A1_header.h"
int main()
{
//small introduction
printf("Welcome to the volume test game\n");
printf("We will start with spheres. \n");
printf("Please input your sphere radius here:");
scanf("%d", &R);
CalcSphVolume(&V, &R);
printf("please input your result:");
scanf("%d", &result);
if(result == V){
printf("Congratulations, your answer is correct!\n");
}
else{
printf("Wrong answer, the correct result was %d \n", V);
}
return 0;
}
Below is my .h file which I use to define functions.
#ifndef Point
#define Point
#include <math.h>
//these are the functions for Sphere calculations
void CalcSphVolume(int V, int R) {
V = 1.33*3.14(R*R*R);
}
void CalcSphRadius(int V, int R) {
R = cbrt(V/4.1762);
return;
}
//these are the functions for the Cone calculations
void CalcConVolume(int V, int R, int H) {
V = 0.33*(3.14*(R*R))H;
return;
}
void CalcConHeight(int V, int R, int H) {
H = V/(0.33*(3.14*(R*R)));
}
void CalcConRadius(int V, int R, int H) {
R = sqrt(V/(0.33*3.14H));
}
//these are the functions for the Cilinder calculations
void CalcCilVolume(int V, int R, int H) {
V = 3.14*H*(R*R);
}
void CalcCilHeight(int V, int R, int H) {
H = V/(3.14(R*R));
}
void CalcCilRadius(int V, int R, int H) {
R = sqrt(V/(3.14*H));
}
#endif
I am not sure how you are running the code, because under ordinary circumstances this code will not compile.
There are a couple of things that are wrong in this code -
void CalcSphVolume(int V, int R) {
V = 1.333.14(RRR);
}
Firstly, I think there might be an error in your formatting, because RRR is not the correct way to compute, what you want is (R*R*R), similarly, 1.333.14 is not an accepted datatype. From context, since it is the volume of a sphere, this should be
void CalcSphVolume(int V, int R) {
V = 1.333 * 3.14 * (R*R*R);
}
Now that this is out of the way, there are some issues with this function (and similar to the other functions in your code.)
You are mixing types here - 1.333 is double, but V is int, so your actual answer will be implicitly converted to an integer, and you will lose precision. So V should be of the type double. So you get a more accurate answer.
void CalcSphVolume(double V, int R) {
V = 1.333 * 3.14 * (R*R*R);
}
Another thing to note here is that your functions parameters are by value and do not accept pointers. This means that any result that you get in this void function, will be lost unless you explicitly return it. Local variables only exist in the scope of the function. Since you are passing a pointer to the function and trying to populate the value outside the function, you should modify the function and function signature to
void CalcSphVolume(double* V, int* R) {
int r = *R // for clarity
*V = 1.333 * 3.14 * (r*r*r);
}
We have to dereference to get the "actual" value that is held by the pointer. You cannot apply arithmetic logic in this manner to raw pointers.
An alternative way to accomplish the same is
double CalcSphVolume(int R) {
double V = 1.333 * 3.14 * (R*R*R);
return V; // or simply return 1.333 * 3.14 * (R*R*R)
}
Here you are passing by value, but returning the value computer back to the caller. So you could use this function like so -
double Volume = CalcSphVolume(R);
This is much more clearer in this case, instead of having to pass pointers all over the place.
For your use case, using pointers is not necessary - consider using pointers when you have to mutate or pass large objects (Imagine a really huge array, so you don't want to create a copy it each time you use it in a function) which cannot be declared on the stack.
The issue is your function parameters are taking in an integer rather than a pointer to the memory address.
What you want to do instead is:
void CalcSphRadius(int *V, int *R)
{
*R = cbrt((*V)/4.1762);
return;
}
Now, the function is taking in a pointer to V and R and will read/write to their memory address.
As shown above, don't forget to dereference your pointers by using an asterisk '*' so that way you are writing to the value stored in those addresses, rather than just doing pointer arithmetic.
You can also retrieve values by using return types for functions.
int CalcSphRadius(int V)
{
return cbrt(V/4.1762);
}
And then use them to assign variables like so:
R = CalcSphRadius(V);
Your .h file name should be A1_header.h
Also, the code can be like this:
#ifndef Point
#define Point
#include <math.h>
#include <stdio.h>
//these are the functions for Sphere calculations
void CalcSphVolume(int V, int R);
void CalcSphRadius(int V, int R);
//these are the functions for the Cone calculations
void CalcConVolume(int V, int R, int H);
void CalcConHeight(int V, int R, int H);
void CalcConRadius(int V, int R, int H);
//these are the functions for the Cilinder calculations
void CalcCilVolume(int V, int R, int H);
void CalcCilHeight(int V, int R, int H);
void CalcCilRadius(int V, int R, int H);
#endif
#include "A1_header.h" in the wrong place.
It should be like
//directives
#include <stdio.h>
#include "A1_header.h"
int main(void)
{
variable declaration;
statements
}
Please try to learn the structure of the C program.
You need to declare the variables inside the main function.
When you call the function CalcSphVolume(V, R); why the address of the variable? It should be:
printf("Please input your sphere radius here:");
scanf("%d", &R);
CalcSphVolume(V, R);
Arrange all the functions properly
eg: CalcCilHeight function should be properly formatted with *
void CalcCilHeight(int V, int R, int H)
{
H = V/(3.14 * (R * R));
}
Related
I wrote a function pointer that has all void* so that it can be used for any numeric value
int
float
double.
But it is working only for the int addition function
For float and double addition functions, it throws compile time error.
Why is that so ?
If you uncomment the last two printf lines, you would receive error
#include<stdio.h>
int int_add(int x, int y) {
return x + y;
}
float float_add(float x, float y) {
return x + y;
}
double double_add(double x, double y) {
return x + y;
}
void* do_operation(void* (*op)(void*, void*), void* x, void* y) {
return op(x, y);
}
void main(void) {
printf("Sum= %d\n",(int*) do_operation(int_add, 1, 2));
/*printf("Sum= %f\n",(float*) do_operation(float_add, 1.20, 2.50));*/
/*printf("Sum= %lf\n",(double*) do_operation(double_add, 1.20, 2.50));*/
}
void * is a pointer type. You're not passing pointers, you're passing values, so that's not going to compile. It accidentally "works" for int because pointers themselves are represented as integers by most C compilers.
If you pass pointers to int, float, and double instead of the int, float, and double themselves, you will avoid that compiler error. You'd also need to change int_add and friends to take pointers, and you'd have to make sure you dereferenced the pointers before using them. You'll also have to return pointers, which means you'll have to malloc some memory on the heap, because the stack memory assigned to your local variables will be invalid once your function exits. You'll then have to free it all later... in the end, this is going to result in something considerably more complicated than the problem it appears you are trying to solve.
I have to ask why you are trying to do this? C is really not the best language for this type of pattern. I'd suggest just calling the int_add, float_add, etc. functions directly instead of trying to abstract them in this way.
So as per #charles-srstka suggestion I rewrote the code and then it worked as I wanted
#include<stdio.h>
#include<stdlib.h>
int* int_add(int *x, int *y) {
int *c = (int *)malloc(sizeof(int));
*c = *(int*)x + *(int*)y;
return c;
}
float* float_add(float *x, float *y) {
float *c = (float*)malloc(sizeof(float));
*c = *(float*)x + *(float*)y;
return c;
}
void* do_operation(void* (*op)(void*, void*), void* x, void* y) {
return op(x, y);
}
void main(void) {
int a = 1;
int b = 2;
int *c;
c = do_operation(int_add, &a, &b);
printf("%d\n",*c);
free(c);
float x = 1.1;
float y = 2.2;
float *z;
z = do_operation(float_add, &x, &y);
printf("%f\n",*z);
free(z);
}
Here's my code :
#include <stdio.h>
#include <stdlib.h>
void *create_array(int size) {
double *v;
v = (double*)malloc(size * sizeof(double));
v[0] = (double)size;
return (void*)v;
}
int main() {
void *a;
double b = 5;
a = create_array(10);
a[1] = b;
return 0;
}
I'm trying to assign the value stored in b to (*a[1]). I get the following error :
"main.c:19:9: error: incomplete type 'void' is not assignable
a[1]=b;"
~~~~^
Main Answer
void is an incomplete type and cannot be used in expressions, including assignments. You can, however, have pointers to this type, void *. void * is a type that means “this points to something, but we are not saying what at this point.”
In order to use a void *, you must say what it points to, by converting it to a different kind of pointer, such as double *, which says “this points to a double.”
C, unlike C++, will do this conversion automatically in assignments. If we declare a with double *a; and then we assign it with a = create_array(10);, then the void * that is returned from create_array is automatically converted to a double * for storing in a. After that, we can write a[1] = b; to store b in the double at a[1].
Supplement
Your create_array contains a mix of double * and void *. It is better to either write a routine that is designed for a specific type:
double *create_array(int NumberOfElements)
{
double *v = malloc(NumberOfElements * sizeof *v);
v[0] = NumberOfElements; // (Yuck, this is ugly.)
return v;
}
or to write a routine that handles any type:
void *create_array(int NumberOfElements, size_t SizeOfElement)
{
void *v = malloc(NumberOfElements * SizeOfElement);
// Cannot store size easily since we do not know what element type is.
return v;
}
As noted, that business about storing the number of elements in the first element is messy. It is better to handle the size separately, even if that requires writing more code.
Also, avoid calling something just a “size,” because this can be confusing: Is the size of an array the number of elements in it or the number of bytes? The name or accompanying comments should always make the unit of measurement clear.
neither pointers nor variables can be void type, just function's return
change to:
#include <stdio.h>
#include <stdlib.h>
double *create_array(int size){
double *v;
v=(double*)malloc(size*sizeof(double));
v[0]=(double)size;
return (double*)v;
}
int main() {
double *a;
double b;
b=5;
a=create_array(10);
a[1]=b;
return 0;
}
You can't dereference a void *, but you can use a cast:
#include <stdio.h>
#include <stdlib.h>
void *
create_array(int size)
{
double *v = malloc(size * sizeof *v);
if( v == NULL ){
perror("malloc");
exit(EXIT_FAILURE);
}
v[0] = (double)size;
return v;
}
int
main(void)
{
void *a;
double b = 5.0;
double *c;
c = a = create_array(10);
((double *)a)[1] = b;
printf("%f %f\n", c[0], c[1]);
return 0;
}
The second piece of code is not giving the correct value as it only passes the value of r from what I see. However, I would like to make this code work without using return (just for learning how to do it in this other way). Also, what is considered best practice between these two options? Thank you! :-)
#include <stdio.h>
#define PI 3.1416
float area(float r);
int main(void)
{
float r = 10;
printf("Area: %.2f", area(r));
return 0;
}
float area(float r) {
return PI * r * r;
}
#include <stdio.h>
#define PI 3.1416
float area(float r);
int main(void)
{
float r = 10;
printf("Area: %.2f", area(r));
return 0;
}
float area(float r) {
PI * r * r;
}
I would like to make this code work without using return (just for learning how to do it in this other way).
Using return is the only way to actually return a value from a function.
However, the C syntax provides two alternative options:
It is possible to pass another pointer as argument to the function, which points to an object in the caller, in which you then assign the value of the expression.
For example:
#include <stdio.h>
#define PI 3.1416
void area(float r, float *p);
int main(void)
{
float r = 10;
float s;
area(r, &s);
printf("Area: %.2f", s);
return 0;
}
void area(float r, float* p) {
*p = PI * r * r;
return;
}
It is also possible to define a global object and assign the value of the expression to that global object instead.
For example:
#include <stdio.h>
#define PI 3.1416
float s;
void area(float r);
int main(void)
{
float r = 10;
area(r);
printf("Area: %.2f", s);
return 0;
}
void area(float r) {
s = PI * r * r;
return;
}
But that is considered to be bad practice because the connections from and to the function and with that the actual use of the function are then much harder to understand than using parameters and return types, which on the other hand show the relation and the use of the particular function call pretty good.
The use of global objects shall be avoided if possible although there are cases where a global objects is suitable, if you f.e. use an object in multiple functions and the role of the object is exactly defined. But in the provided example of yours, a global object does not fit very well and shall be avoided.
If no value shall be returned, define the return type of the function as of type void.
I'm working on a simple library which operate on vectors.
It define a type of function that is regularly used:
typedef float (*vec_pair_fun) (float x, float y);
For ease-of-use reason, I want to create a sorting function that use a vec_pair_fun to compare each element of a vector.
At the moment, I'm doing this:
static vec_pair_fun sort_function;
// follow improvements suggested by #chux below
static int converted_sort_function(const void* a, const void* b){
//old code: return (int) qsort_function(*(float*)a,*(float*)b);
float f = sort_function(*(float*)a,*(float*)b);
return (f > 0.0f) - (f < 0.0f);
}
void vecx_sort(int x, float v[], vec_pair_fun func){
sort_function=func;
qsort(v,x,sizeof(float),converted_sort_function);
}
but I don't really like that workaround because it's not threadsafe as sort_function can be changed by another thread.
Any idea on how to improve this?
EDIT:
One way would be to sort the array myself.
Recoding qsort is really not what I planned to do, so I'm really open for suggestions
Q: Any idea on how to improve this?
A: Do not cast float result to int for compare.
Maybe not OP's main concern but (int) sort_function(*(float*)a,*(float*)b); is weak.
The FP point result could be -0.4 or 0.4, both of these convert to (int) 0.
The FP point result could be > INT_MAXand conversion to int is UB.
Suggest:
static int converted_sort_function(const void* a, const void* b){
float f = sort_function(*(float*)a,*(float*)b);
return (f > 0.0f) - (f < 0.0f);
}
As to your thread safe problem, consider qsort_s() which passes in a context pointer. qsort_s() is specified in C11 Annex K, so it may not exist in your compiler.
errno_t qsort_s(void *base, rsize_t nmemb, rsize_t size,
int (*compar)(const void *x, const void *y, void *context),
void *context);
Following wikibooks 5th C implementation and Apple's implementation of a quicksort algorithm, I was able to create my function.
It appear to be quicker than the stdlib version, and it has no global/static variable.
// x: length of v
// v: array of float
// func: a function that takes two float as argument and return a float
void vecx_qsort(unsigned int x, float v[], vec_pair_fun cmpf)
{
float pivot,tmp;
unsigned int al,l,r,ar,cnt;
while (x>8)
{
cnt=0;
al=l=1; r=ar=x-1;
pivot=v[x/2];
v[x/2]=v[0];
v[0]=pivot;
while (1)
{
while ( l<=r && (tmp=cmpf(v[l],pivot))<=0.0f ) {
if(tmp==0.0f){
cnt=1;
vecx_swap(1,v+al,v+l); //swap vl & val
al++;
}
l++;
}
while ( l<=r && (tmp=cmpf(v[r],pivot))>=0.0f ) {
if(tmp==0.0f){
cnt=1;
vecx_swap(1,v+r,v+ar);//swap vr & var
ar--;
}
r--;
}
if(l>r)
break;
cnt=1;
vecx_swap(1,v+r,v+l);
l++; r--;
}
if(cnt==0 && x<=32) // no swap made => almost sorted small array => insertion sort
break;
// swap values equal to pivot to the center
cnt = (al<(l-al))?al:l-al;
vecx_swap(cnt,v,v+l-cnt); // swap of element before al
cnt = ((ar-r)<(x-ar-1))?ar-r:x-ar-1;
vecx_swap(cnt,v+l,v+x-cnt); // swap of element after ar
l=l-al; // size of "smaller element array"
r=ar-r; // size of "bigger element array"
// Recursion on the shorter side & loop (with new indexes) on the longer
if (l>r) {
vecx_qsort(r, v+x-r, cmpf);
x=l;
}
else {
vecx_qsort(l, v, cmpf);
v+=x-r;
x=r;
}
}
// insertion sort
for (r=1; r<x; r++)
{
pivot=v[r];
for(l=r; l>0 && cmpf(pivot,v[l-1])<0.0f; l--)
v[l]=v[l-1];
v[l]=pivot;
}
}
I am trying to calculate the exponent of a number. When I do everything as int I get the correct result, but the output must be float, when I try to convert with %f in printf() I get 0, when I use %d I get the correct result. I cannot change the main() portion of the program, I can only alter the *powerArgs() function. The program input is 3, 5.
Full disclosure, this is part of a school assignment. I am not asking for complete code. I would appreciate a more general answer showing me what I am forgetting, possibly what area I should study more to find the answer myself.
#include <stdio.h>
#include <stdlib.h>
int *powerArgs(int *pA, int *pB);
/* MAIN */
int main(int argc, char **argv)
{
if (argc != 3)
{
printf("?Invalid number of arguments\n");
system("pause");
exit(1);
}
int parmA = atoi(argv[1]);
int parmB = atoi(argv[2]);
int idx;
/* Part C: Raise parmA to the power of parmB. Return pointer to the result */
/* Reset the original values after we print the result */
printf("%d raised to the %d power is %0.1f\n", parmA, parmB, *powerArgs(&parmA, &parmB));
printf("\n");
system("pause");
exit(0);
}
int *powerArgs(int *pA, int *pB)
{
int idx, result = *pA;
for (idx = 1; idx < *pB; idx++)
{
result *= *pA;
}
return &result;
}
float and int convert automatically in C - you can assign either one to the other, and the only thing to watch out for is that if you assign too large a float to an int, then you get undefined behavior (or possibly an unspecified result, I forget. Either way it's not good).
So, your powerArgs function can just be:
float powerArgs(float a, int b) {
// do some stuff and return a value
}
Then you can call it as powerArgs(parmA, parmB), even though parmA is an int.
Edit: if you can't change the call parameters, you can do this instead
float powerArgs(int *a, int *b) {
float base = *a;
int exponent = *b;
...
}
If your professor has really set you code where the function is called as *powerArgs(int *a, int *b), then your professor is a menace. There is no earthly reason why an exponentiation function should return a pointer to a float. There's an ugly workaround you could use:
float *powerArgs(int *a, int *b) {
static float result;
...
result = /* the result of the calculation */;
return &result;
}
The problem with this is, all calls to powerArgs share the same object result. static stops it from ceasing to exist at the end of the call, but the sharing will introduce problems in the long run. It is not good practice to do this, but it might be the best solution to the problem you've been set.
C++ sneaky solution:
struct FloatWrapper {
float value;
float operator*() {
return value;
}
FloatWrapper(float f) : value(f) {}
};
FloatWrapper powerArgs(int *a, int *b) {
...
float result = /* whatever */;
...
return result;
}
This returns an object of class FloatWrapper, by value, and FloatWrapper overloads the * operator. This means that *powerArgs(...) evaluates to the float that the function should have returned by value in the first place, without needing a pointer to any special storage place.
By the way, you might want to check what your function does when parmB is 0.
First, your int *powerArgs(int *pA, int *pB) function returns the address of a local variable, which results in undefined behavior. Use the following instead:
int powerArgs(int *pA, int *pB)
{
int idx, result = *pA;
for (idx = 1; idx < *pB; idx++)
{
result *= *pA;
}
return result;
}
Next, if you want to convert to float, you shouldn't do that in the call to printf(), but rather convert the value to float before the call like so:
printf("%d raised to the %d power is %0.1f\n", parmA, parmB, (float)powerArgs(&parmA, &parmB));
When a function terminates, all its local variables cease to exist (and their addresses point to garbage). To please your teacher who came up with that very awkward interface, you have to find a way to keep an object alive after the function exists.
You have, at least, 3 options:
a) reuse one of the input parameters
b) use a global variable
c) use a static variable
option a)
int *powerArgs(int *pA, int *pB) {
/* calculate */
*pA = CALCULATED_VALUE;
return pA;
}
option b)
int global_power;
int *powerArgs(int *pA, int *pB) {
/* calculate */
global_power = CALCULATED_VALUE;
return &global_power;
}
option c)
int *powerArgs(int *pA, int *pB) {
static int static_power;
/* calculate */
static_power = CALCULATED_VALUE;
return &static_power;
}
Neither of these "solutions" is good; the least bad is option c)