2010-04-24 12 views
20

Supongamos que tengo la siguiente estructura y función que devuelve un puntero:devolviendo un puntero estructura

typedef struct { 
    int num; 
    void *nums; 
    int size; 
} Mystruct; 

Mystruct *mystruct(int num, int size) 
{ 
    //Is the following correct? Is there a more efficient way? 
    Mystruct mystruct; 
    mystruct.num = num; 
    mystruct.size = size; 
    mystruct.nums = malloc(num*sizeof(size)); 
    Mystruct *my; 
    *my = mystruct; 
    return my; 
} 

quiero definir cualquier puntero myStruct usando la función anterior. ¿Debo declarar una variable Mystruct, definir las propiedades de Mystruct, asignarle un puntero y devolver el puntero o definir las propiedades de una propiedad mystruct a través de un puntero inmediatamente?

+1

Quizás podría codificar ambas opciones. De la descripción, no está claro lo que estás intentando. –

+0

Y recuerde ... nunca propague un puntero "desde la pila" hacia arriba. –

Respuesta

34

¿Debo declarar una variable myStruct, definir las propiedades de myStruct, asignar un puntero a ella, y regresar el puntero

Definitivamente no, porque la variable se define en la función (en clase de almacenamiento "automático") desaparecerá cuando la función finalice, y devolverá un puntero colgante.

Puede aceptar un puntero a Mystruct (la responsabilidad del que llama para asignar eso) y completarlo; o bien, puede usar malloc para crear uno nuevo (la responsabilidad del llamador es liberarlo cuando esté listo). La segunda opción, al menos, le permite mantener la firma de la función que pareces estar interesado en:

Mystruct *mystruct(int num, int size) 
{ 
    Mystruct *p = malloc(sizeof(MyStruct)); 
    .... 
    return p; 
} 

pero es a menudo un inferior uno - ya que la persona que llama tiene que tener responsabilidades de todos modos, puede ser que también vaya con la primera opción y potencialmente puede obtener rendimiento (si la persona que llama puede usar una instancia de autoclase porque sabe que el alcance de uso está limitado).

+0

¿por qué escribiste malloc con (Mystruct *)? ¿Es eso necesario? – idealistikz

+0

@idealistikz: No, no es necesario. – sth

+5

No es necesario en C (y a menudo se considera un estilo incorrecto en ese idioma), pero lo contrario es cierto en C++. – caf

2

La asignación de un nuevo Mystruct y devolver un puntero a que por lo general se verá más o menos así:

Mystruct *mystruct(int num, int size) 
{ 
    Mystruct *result; 

    result = malloc(sizeof(MyStruct)); 
    if (!result) 
    return NULL; 

    result->num = num; 
    ... 

    return result; 
} 

Más tarde, cuando haya terminado con el Mystruct asignado aquí con malloc, debe ser liberado de nuevo con free().

Simplemente declarar una variable local y devolver un puntero a esa variable local no funcionará. La variable local sale del alcance al final de la función y es muy probable que la memoria donde se almacenó se reutilice para otros fines. El puntero devuelto seguirá apuntando a la ubicación de la memoria donde una vez estuvo la variable local, pero como esa variable ya no existe, ese puntero no sería de mucha utilidad.

2

Es importante recordar que el puntero no es algo que le asigna a la estructura, sino que el puntero indica la ubicación en la memoria que desea tratar como una estructura. Según su pregunta, realmente desea asignar la memoria para mantener la estructura de datos. Esto le da un puntero a la ubicación de la memoria asignada. Una vez que tienes eso, puedes devolverlo.


EDITAR (después de editar a la pregunta original) En cuanto a su edición en cuestión, que sin duda tendrá problemas con el "mi" puntero. Esto no está inicializado, y puede apuntar a cualquier lugar en la memoria. Cuando intente copiar la estructura, probablemente obtenga un seg-fault.

6

No puede usar la variable porque se desasignará cuando la función finalice.Por ejemplo:

Mystruct *mystruct(int num, int size) 
{ 
    MyStruct x; 
    x.num = 1; 
    ... 
    return &x; 
} 

dará un fallo de segmentación o la violación de acceso porque la memoria para x se cancela la asignación tan pronto como salida. Por lo tanto, debe asignar memoria para la estructura (y asegúrese de liberarla más adelante) o declare un sistema global que permanecerá para siempre. Ejemplo de este último ...

Mystruct *mystruct(int num, int size) 
{ 
    MyStruct *x; 
    x = (MyStruct*)malloc(sizeof(MyStruct)); 
    x->num = 1; 
    ... 
    return x; 
} 
+2

en realidad 'return * x' no se compilará en la primera función (supongo que quiere decir' return & x'? ** que ** dará el error más sutil que piense, o más probablemente incluso errores más sutiles). –

+0

Whoops, tienes razón - return & x. – staticman

2

una forma más de hacerlo ..

int mystruct(Mystruct *mystruct, int num, int size){ 
    if(mystruct == NULL) 
     return -1; 

    mystruct->num = num; 
    mystruct->size = size; 
    :: 
    return 0; 
} 

int main(){ 
    Mystruct my; 

    if(mystruct(&my, 3, 4) != 0){ 
     fprintf(stderr, "Cannot init!\n"); 
     exit(0); 
    } 
    :: 
} 
3

Si va a escribir código genérico y que no saben cómo se puede usar, es bueno proporcionar dos opciones:

int mystructm(Mystruct *storage, int num, int size) 
{ 
    int rv = 0; 

    storage->num = num; 
    storage->size = size; 
    storage->nums = malloc(num*sizeof(size)); 
    if (!storage->nums) 
     return -1; 

    return 0; 
} 

Mystruct *mystruct(int num, int size) 
{ 
    Mystruct *mp = (Mystruct *)malloc(sizeof(Mystruct)); 
    if (mp) 
    { 
     if (mystructm(mp, num, size) == -1) 
     { 
      free(mp); 
      mp = NULL; 
     } 
    } 

    return mp; 
} 

la idea es que como escritor biblioteca, no debe dictar la política (como la que cada myStruct debe asignarse dinámicamente), pero debe dejar que el escritor de aplicaciones que decidir.

Cuestiones relacionadas