The first problem of calcularFn
is that the array is ill-sized:
float *calculaFn(int n ,Algoritmo a, Caso c){
float fn[2]; // <<--- 1
if(a==INSERCION){
if(c==ORDEN_ASC){ // f(n)'s algoritmo insercion orden ascendente
fn[0] = log(n);
fn[1] = n;
fn[2] = (n*log(n)); // <<--- 2
Although in 1
it is seen that fn
is an array for two elements of type float
, in 2
we see how a third element is given value. This third element does not belong to the array, so its value can overwrite other variables and vice versa.
fn
should have capacity for 3 elements instead of only 2.
As you have been told, fixed-size arrays such as fn
are treated as if they were pointers. In fact, you can easily verify that you can use pointers to point to the content of fn
:
float fn[2];
float* ptr = fn; // OK, el compilador no se queja
Well, returning &n
implies returning a double pointer float **
and for the compiler, a double pointer like float**
is not convertible to a simple pointer 'float *
float *calculaFn(int n ,Algoritmo a, Caso c){
float fn[3];
...
return &fn; // &(float[]) == &(float*) == float**
}
Then, of course, what appears to be the quick solution is to eliminate the indirection:
float *calculaFn(int n ,Algoritmo a, Caso c){
float fn[3];
...
return fn;
}
But then we come across another problem, and that is that fn
is a local variable whose life is restricted to the call calculaFn
. That is, when the program leaves this function, the variable fn
ceases to exist and the memory it occupied can be used without restrictions by other variables.
To achieve your purposes, in legal , that is, without making rare devices, you have several options:
1. Use dynamic memory
If you convert the fixed-size array into a true pointer and redirect it to heap (dynamic memory), you will no longer have problems because you are responsible for managing the life of the memory hosted in the heap :
float *calculaFn(int n ,Algoritmo a, Caso c){
float* fn = new float[3];
...
return fn;
}
However, do not forget to release the memory when it is no longer necessary:
float* ptr = calculaFn(/* ... */);
// ...
delete[] ptr;
2. Use static
The other possibility is that the variable is static. Being static no longer stays in the program's stack but in a different memory region, so that its memory will not be released until the program finishes ... yes, the variable will only be accessible from calculaFn
.
The trick is that calculaFn
returns a pointer to the memory region where the variable is hosted, so its values can be retrieved and / or modified from outside the function:
float *calculaFn(int n ,Algoritmo a, Caso c){
static float fn[3];
...
return fn;
}
Since we have not used new[]
it is not necessary to use delete
. This solution is probably the one that best suits your code. Of course, given that the variable is static, there will only be one instance of it, so you have to be careful not to step your content without wanting to:
float* ptr1 = calculaFn(/* parametros */);
std::cout << ptr1[0] << ' ' << ptr1[1] << ptr1[2] << '\n';
// Esta llamada modifica los valores de ptr1
float* ptr2 = calculaFn(/* otros parametros */);
std::cout << ptr1[0] << ' ' << ptr1[2] << ptr1[2] << '\n';
3. Use data structure
Data structures exist for something, and this would be a clear use case. Unlike fixed-size arrays, data structures can be copied without problems. Notice that it would no longer be necessary to use pointers:
struct DatosFn
{
float dato1;
float dato2;
float dato3;
};
DatosFn calculaFn(int n, Algoritmo a, Caso c)
{
// ...
}
4. Use std :: Array
I wanted to leave for the end the one that, from my point of view, is the best solution. From C ++ 11, std::array
is available. This container brings together the best of fixed-size arrays with the best of object-oriented programming. The result is a fixed-size array with a whole set of utilities that simplify its use.
In summary, objects of type std::array
:
- Can be copied
- Its access is equivalent to that of fixed-sized arrays
- Have iterators
A possible example of implementation:
std::array<float,3> calculaFn(int n, Algoritmo a, Caso c)
{
std::array<float,3> fn;
if(a==INSERCION){
if(c==ORDEN_ASC){ // f(n)'s algoritmo insercion orden ascendente
fn[0] = log(n);
fn[1] = n;
fn[2] = (n*log(n));
// ...
}
return fn;
}