Whatever compiler you're using, turn on its optional warnings (diagnostics, whatever your compiler calls them)! No halfway decent compiler would accept this code without complaining, but unfortunately many compilers default to emitting very few warnings.
GCC does point out the problem, even by default.
a.c:18:54: warning: format ‘%f’ expects argument of type ‘double’, but argument 2 has type ‘float (*)(double, double, const double)’ [-Wformat=]
18 | printf("The total surface area of the cone is %.2f", coneSurfaceAre);
| ~~~^ ~~~~~~~~~~~~~~
| | |
| | float (*)(double, double, const double)
| double
In case you're not familiar with the syntax: float (*)(…) is the type of a pointer to a function taking arguments as described inside the second pair of parentheses, and returning a float value. coneSurfaceAre is a function, and since C mostly doesn't manipulate functions as such, a function is treated as a pointer to the function in most contexts.
The printf function expects a value of type double, but you're passing a pointer to a function. Depending on the system, this may result in printing a meaningless value, a crash, the program continuing but with corrupted memory, etc.
When you want the value returned by a function, you need to call this function, passing it arguments. Using the same names for variables in the main function and in the coneSurfaceArea function may help humans, but as far as the computer is concerned, these are completely different variables.
printf("The total surface area of the cone is %.2f",
coneSurfaceArea(radius, height, pi));
You could pass other values if you wanted.
printf("The total surface area of a cone with twice the height is %.2f",
coneSurfaceArea(radius, 2 * height, pi));
By the way, printf with the %f format expects a double argument¹. Here, you're passing a float. This is actually correct because of promotions: when you pass certain “small” types to a function like printf that takes a variable number of arguments, they are promoted to a larger type, e.g. short to int and float to double. But in more complex cases you could run into problems if you aren't careful. It's generally simpler to stick to double. And using double all the time is often slightly faster than using float, because using float just results in the same calculations followed by a conversion. There is an advantage to float when the program manipulates a lot of numbers, because then you can save memory and, in some cases, take advantage of vector instructions that can perform two independent float operations just as fast as one double operation.
¹ Unlike scanf, which does need a pointer to float for %f, and a pointer to double for %lf.