C does not allow returning arrays from functions. An array can be allocated in the calling function, or the array can be dynamically allocated in the function and a pointer to the returned array. Note that the array that is defined in the function is local, and returning a pointer to such an array is useless, since local variables cease to exist after the function returns. Dynamic distributions, on the other hand, continue to exist. The third option is to use the fact that although arrays cannot be returned from functions in C, a struct can be returned from functions and assigned.
Define an array in the caller
A simple solution is to define an array in the calling function. This array will be modified in the rot_3x3_a() function. Note that instead of relying on a user who is mindful of null array initialization, memset() (defined in string.h ) is used inside the function for a null array.
Using this method has the advantage of avoiding dynamic allocation and the need to free it later to avoid memory leaks. All methods require that the variable be declared in the calling function that receives the rotation matrix, but this method also requires that the array be passed to the function, so this may not meet the OP requirements.
Dynamic allocation
A more attractive solution is to use dynamic allocation. The rot_3x3_b() function accepts only the int argument, as the OP example suggests, but returns a pointer to an array of 3 double (this is a pointer type, which in most expressions decomposes into a 3x3 array). typedef used here, so Matrix_3x3 is a pointer to an array of 3 double s; this makes it easy to write a function prototype.
Here memset() could be used with malloc() , but calloc() was used instead, which automatically initializes the selection to zero. Note that in the function rot_3x3_b() , if the distribution is not executed, nothing happens and a null pointer is returned. The caller must verify this and handle the error accordingly.
The advantages of using this approach are that the resulting matrix distribution can simply be indexed as a 2d array, and the arguments to the function meet OP requirements. The disadvantages are that it is somewhat more complicated for the code than other solutions, and more prone to errors, and the user of this function must remember the free allocated memory in order to avoid memory leaks.
Array flow in structure
As long as C does not allow you to assign an array to another array, a struct can be assigned to another struct . In addition, a struct is an l value that can be returned from a function. So, one of the solutions to the problem is to create a struct containing a 3x3 array in the rot_3x3_c() function. The element of the struct array can be populated before returning the struct function from the function. In this case, the designated initializer was used to zero initialize the element of the struct array.
The advantage here is ease of implementation. There is no dynamic allocation, so no need to worry about memory leaks. The disadvantage is that the array must be accessible as a member of struct , so the user of this function must declare struct Mtrx_3x3 R_c to get the value returned by the function, and must remember to access the array using R_c.mx .
Regarding the M_PI constant
The C standard not only does not define this constant, but provides that the corresponding implementation should not define it by default. This means that if a particular implementation defines an M_PI , it is an extension that must be explicitly included. As a general extension, this constant is defined. For example, if compiled with gcc -std=gnu11 , there is no need to explicitly enable M_PI . But if one of the more strict parameters is used, for example, gcc -std=c11 , M_PI must be explicitly included. Here is a question that discusses the problem .
Now _USE_MATH_DEFINES works with Microsoft implementations, but does not work with GCC on Linux (as far as I know). For greater portability, note that M_PI is defined in POSIX . This can be activated using the _XOPEN_SOURCE 700 function test macro. Or add as the very first line in the source file:
#define _XOPEN_SOURCE 700
or enable from the command line when compiling with:
gcc -std=c11 -D_XOPEN_SOURCE=700
Please note that when using #define to enable functions, it must be at the very beginning of the source file. Of course, here you can use -std=c99 or -std=c89 instead of std=c11 .
This will work on Linux systems that closely match POSIX, but I'm not sure if it will work on Microsoft systems, which follows POSIX much less closely. For maximum portability, it's best to simply define the constant explicitly using:
#define M_PI 3.14159265358979323846
Program example
Here is a program that illustrates each of the above approaches:
#include <stdio.h>
Program output:
Method a: pass an array 0.86603 0.50000 0.00000 -0.50000 0.86603 0.00000 0.00000 0.00000 0.00000 Method b: use dynamic allocation 0.86603 0.50000 0.00000 -0.50000 0.86603 0.00000 0.00000 0.00000 0.00000 Method c: wrap the array in a struct 0.86603 0.50000 0.00000 -0.50000 0.86603 0.00000 0.00000 0.00000 0.00000