2011-02-10 12 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; 
} 

To jest uproszczona wersja kodu, który daje mi problemy. Próbuję skonstruować wskaźnik *list z metody, gdzie *list jest przekazywany jako parametr.C - Nie można zainicjować wskaźnika przekazanego jako argument

Wiem, że mogę wykonać void init(List *l) pracę, zmieniając go na void init(List **l), ale to jest dla samouczka klasy. Nie mogę zmienić argumentów metody. Spędziłem cztery godziny nad tym.

Chcę się upewnić, że nie ma sposobu, aby wykonać void init(List *l) pracę, zanim skonfrontuję mojego profesora.

góry dzięki

Odpowiedz

4

Ty przekazując kopię wskaźnika do init, który przydzielania pamięci, przechowując je w swojej lokalnej kopii, i szybko przecieka to kiedy init powraca. W ten sposób nie można przekazać danych do funkcji wywołującej. Musisz albo zwrócić przydzielone dane, albo przekazać wskaźnik do wskaźnika, który chcesz zmodyfikować, z których oba wymagają modyfikacji podpisu funkcji.

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

init(&list); 

Czy zadanie określić, że trzeba przeznaczyć List od wewnątrz init? Jeśli nie, zawsze można przekazać wskaźnik do już przydzielone List obiektu i wykonać niezależnie od inicjalizacji length = 3 jest miejsce dla posiadacza:

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

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

PO specjalnie wymienione, jeśli można tego uniknąć, unikając "void init (List ** l)" –

+0

@Gunner adresowany – meagar

+0

Przypisanie określa, że ​​musi to być konstruktor. Zamierzam wysłać do mojego profesora maila i poprosić go o zmianę wymagań. Dzięki za pomoc! –

3

Problemem jest to, że wskaźnik jest przekazywane przez wartość, więc jesteś zmiany są odrzucane. Naprawdę potrzebujesz wskaźnika do wskaźnika, aby zrobić to poprawnie. Jak w zrobiłbyś:

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

A gdy go nie nazywać, należałoby użyć init(&list) zamiast init(list). Oczywiście, w tym przypadku, to ma sens tylko iść do przodu i zwraca wynik, zamiast używać wskaźnik do wskaźnika:

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

a następnie z powyższym, można po prostu użyć list = init();.

Należy zauważyć, że w języku C++ można używać odwołań zamiast wskaźników, ale mieszanie odniesień i wskaźników jest niewiarygodnie kłopotliwe. W tym przypadku używanie zwrotu jest naprawdę najmądrzejszą rzeczą do zrobienia.

Jeśli bezwzględnie musisz użyć istniejącego podpisu, możesz być sprytny i zainicjować listę, a następnie w funkcji init() możesz wskazać następny wskaźnik listy, którą chcesz utworzyć. Następnie, po wywołaniu init(), można wziąć następny wskaźnik i zutylizować pierwotny obiekt listy, który utworzyłeś. Lub zawsze możesz po prostu mieć pierwszy element przez jakiś fałszywy element.

1

to zadanie jest prawdopodobnie dobrym sposobem na nauczenie w klasie przejścia według wartości i przejścia przez odniesienie. Jeśli chcesz zachować podpis konstruktora, musisz zmodyfikować główną funkcję.

#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; 
} 

Teraz tutaj jest lista typu, a nie adres do listy. metoda init() przekazała adres listy i wewnątrz init można zmienić wartość zawartości struktury.

./a.out

długość końcowa 3

+0

Uważam ten zbiór za naruszenie hermetyzacji. init jest odpowiedzialny za zainicjowanie zawartości listy; jeśli potrzebny jest zestaw memów, powinien to zrobić. Jak to jest, nie jest potrzebne. –

0

startowych należy przekazać wskaźnik do istniejącej listy. Podejrzewam, że prawdziwym problemem jest tutaj struktura danych. Masz coś zwanego Listą, która zawiera długość, ale nigdzie nie widać żadnej listy. Lista powinna prawdopodobnie zawierać wskaźnik do tablicy o podanej długości, a init powinien zaimportować tę tablicę i ustawić wskaźnik. Prawdopodobnie dowiesz się tego, kiedy poprosisz profesora, aby poprawił swoje wymagania, które nie są zepsute - gdyby tak było, prawdopodobnie usłyszałby o tym od byłych uczniów i poprawił je do tej pory.

Powiązane problemy