Warning pointers c

1

I have a problem in the following code and I need help to fix it. Thanks in advance

float *calculaFn(int n ,Algoritmo a, Caso c){   

  float fn[2];  
  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));   
    }else if(c==ORDEN_RAND){  // f(n)'s algoritmo insercion orden 
  aleatorio  
        fn[0] = (n*log(n));   
        fn[1] = (pow(n,2));   
        fn[2] = (pow(n,2.1));  
    }else{ // f(n)'s algoritmo insercion orden descendente  
        fn[0] = pow(n,1.8);  
        fn[1] = pow(n,2);     
        fn[2] = pow(n,2.2);   
    }  
  }else{  
    if(c==ORDEN_ASC){  //algoritmo rapido orden ascendente  
      fn[0] = pow(n,.8);   
      fn[1] = pow(n,.92)*log(n);  
      fn[2] = pow(n,1.2);     
    }else if(c==ORDEN_RAND){ // f(n)'s algoritmo rapido orden aleatorio  
      fn[0] = pow(n,.8);  
      fn[1] = pow(n,.92)*log(n);  
      fn[2] = pow(n,1.2);    
    }else{ // f(n)'s algoritmo rapido orden descendente  
      fn[0] = pow(n,.8);   
      fn[1] = pow(n,.92)*log(n);  
      fn[2] = pow(n,1.2);      
    }  
  }  
  return &fn;     <------Me salta el siguiente warning aqui  
}  
  

p2.c: In function 'calculaFn':
  p2.c: 227: 10: warning: return from incompatible pointer type [-Wincompatible-pointer-types]
  return & fn;
  --------- ^
  p2.c: 227: 10: warning: function returns address of local variable [-Wreturn-local-addr]

    
asked by Carlos 24.10.2018 в 12:56
source

2 answers

2

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; 
} 
    
answered by 25.10.2018 в 07:38
2
float *calculaFn(int n ,Algoritmo a, Caso c){   
  float fn[2];
  ...
  return &fn;
}

Two problems:

  • In C / C ++, an array is effectively a pointer. That is, return fn; is (so it refers to types), correct. When you add an indirection, what you return is float ** .

  • fn is defined as a local variable. In the stack . That means that, once you exit the method, those stack positions will be available for use by other methods. That they will be able to overwrite them.

    Eg try to add a method

    float *machacaFn(int n, Algoritmo a, Caso c) {
      float otroNombre[2];
      otroNombre[0] = 42.0;
      otroNombre[1] = 69.0;
      return NULL;
    }
    

    and

    float miFloat1, miFloat2, *fn2;
    fn2 = calculaFn(1, a, c);
    machacaFn(1, a, c);
    miFloat1 = *fn2;
    fn2++;
    miFloat2 = *fn2;
    cin << miFloat1 << " - " << miFloat2 << endl;
    

    In the call to machacaFn , the variable otroNombre will occupy the same position of memory that occupied fn and when writing in it you will overwrite the values returned by the function calculaFn .

    If you want to define a variable that persists after the method call, you have to get it from the heap , either with malloc or new .

answered by 24.10.2018 в 14:03