2011-02-10 15 views
5
#include <stdio.h> 
#include <stdlib.h> 
typedef struct { 
    unsigned length; 
} List; 
void init(List *l) { 
    l = (List *) malloc(sizeof(List)); 
    l->length = 3; 
} 
int main(void) { 
    List *list = NULL; 
    init(list); 
    if(list != NULL) { 
     printf("length final %d \n", list->length); 
     return 0; 
    } 
    return 1; 
} 

Esta es una versión simplificada del código que me está causando problemas. Estoy intentando construir el puntero *list a partir de un método donde se pasa *list como parámetro.C - No se puede insertar un puntero pasado como argumento

Sé que puedo hacer que void init(List *l) funcione al cambiarlo a void init(List **l), pero esto es para un tutorial de clase. No puedo cambiar los argumentos del método. He pasado cuatro horas trabajando en esto.

Quiero asegurarme de que no hay forma de hacer que void init(List *l) funcione antes de enfrentarme con mi profesor.

Gracias de antemano

Respuesta

4

estás pasando una copia del puntero a init, que es la asignación de memoria, almacenándolo en su copia local, y rápidamente se escapa cuando init devoluciones. No puede pasar datos de vuelta a la función de llamada de esta manera. Debe devolver los datos asignados o pasar un puntero al puntero que desea modificar, y ambos implican modificar la firma de la función.

void init(List **l) { 
    *l = (List *) malloc(sizeof(List)); 
    (*l)->length = 3; 
} 

init(&list); 

quiso especificar la asignación que usted tiene que asignar el List desde dentro init? Si no, siempre se puede pasar un puntero a un objeto List ya asignados, y realizar cualquier inicialización length = 3 es como un comodín para:

void init(List *l) { 
    l->length = 3; 
} 

List list; 
init(&list); 
printf("length final %d \n", list.length); 
+1

El PO se menciona específicamente si se puede hacer evitando "void init (List ** l)" –

+0

@Gunner direccionado – meagar

+0

La asignación especifica que debe ser el constructor. Voy a enviar un correo electrónico a mi profesor y pedirle que cambie los requisitos. ¡Gracias por tu ayuda! –

3

El problema es que el puntero se pasa por valor, por lo que está los cambios son descartados Realmente necesita un puntero a un puntero para hacer esto correctamente. Al igual que en lo haría:

void init(List** l) { 
    *l = (List*) malloc(sizeof(List)); 
    // ... 
} 

Y cuando usted lo llama, se usaría en lugar de init(&list)init(list). Por supuesto, en este caso, tiene sentido sólo seguir adelante y devolver el resultado en lugar de utilizar un puntero a un puntero:

List* init() { 
    List* result = (List *) malloc(sizeof(List)); 
    result->length = 3; 
    return result; 
} 

Y luego, con lo anterior, se puede simplemente utilizar list = init();.

Tenga en cuenta que en C++, puede utilizar referencias en lugar de punteros, pero mezclar referencias y punteros es increíblemente desordenado. Aquí, usar un tipo de retorno es realmente lo mejor que se puede hacer.

Si tiene que usar la firma existente, puede ser sigiloso e inicializar la lista, luego en la función init() puede hacer que el siguiente puntero de la lista pasada apunte a la lista que realmente desea crear. Luego, después de haber llamado al init(), puede tomar el siguiente puntero y deshacerse del objeto de la lista original que creó. O siempre puedes tener el primer elemento mediante un elemento ficticio.

1

esta asignación es probablemente una buena manera de enseñar en una clase el pase por valor y pasar por referencia. Si desea mantener la firma del constructor, debe modificar la función principal.

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
typedef struct { 
    unsigned length; 
} List; 


void init(List *l) { 
    l->length = 3; 
} 
int main(void) { 
    List list;// x = NULL; 
    memset(&list,0,sizeof(List)); 
    init(&list); 
    printf("length final %d \n", list.length); 
    return 1; 
} 

Ahora aquí la lista es de tipo Lista y no dirección a Lista. el método init() pasó la dirección de la lista y dentro de init puede cambiar el valor de los contenidos de la estructura.

./a.out

longitud final 3

+0

Considero que memset es una violación de la encapsulación. init es responsable de ingresar el contenido de la lista; si se necesita un memset, debería hacerlo. Como es, no es necesario. –

0

init tiene que ser pasado un puntero a una lista existente. Sospecho que el verdadero problema aquí es con su estructura de datos. Tienes algo llamado Lista, que contiene una longitud, pero no hay una lista para ver en ningún lado. La lista probablemente debería contener un puntero a una matriz de la longitud dada, e init debería malloc esa matriz y establecer el puntero. Probablemente descubrirá esto cuando le pida al profesor que corrija sus requisitos, que no están rotos. Si lo fueran, probablemente ya los hubiera escuchado sobre los alumnos anteriores y los corrigiera ahora.

Cuestiones relacionadas