C - не может инициировать указатель, который передается в качестве аргумента - PullRequest
5 голосов
/ 10 февраля 2011
#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;
}

Это упрощенная версия кода, которая доставляет мне проблемы. Я пытаюсь создать указатель *list из метода, в котором *list передается в качестве параметра.

Я знаю, что могу заставить void init(List *l) работать, изменив его на void init(List **l), но это для учебника класса Я не могу изменить аргументы метода. Я провел четыре часа, работая над этим.

Я хочу убедиться, что нет способа заставить void init(List *l) работать до того, как я столкнусь с моим профессором.

Заранее спасибо

Ответы [ 4 ]

4 голосов
/ 10 февраля 2011

Вы передаете копию указателя init, который выделяет память, хранит ее в локальной копии и сразу же выдает, когда возвращается init. Вы не можете таким образом передавать данные обратно вызывающей функции. Вам нужно либо вернуть выделенные данные, либо передать указатель на указатель, который вы хотите изменить, оба из которых включают изменение сигнатуры функции.

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

init(&list);

Указывало ли назначение, что вы должны выделить List из init? Если нет, вы всегда можете передать указатель на уже выделенный объект List и выполнить любую инициализацию length = 3 в качестве заполнителя для:

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

List list;
init(&list);
printf("length final %d \n", list.length);
3 голосов
/ 10 февраля 2011

Проблема в том, что указатель передается по значению, поэтому ваши изменения отменяются. Вам действительно нужен указатель на указатель, чтобы сделать это правильно. Как и вы бы:

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

И когда вы звоните, вы бы использовали init(&list) вместо init(list). Конечно, в этом случае имеет смысл просто пойти дальше и вернуть результат вместо использования указателя на указатель:

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

И затем, с учетом вышесказанного, вы можете просто использовать list = init();.

Обратите внимание, что в C ++ вы можете использовать ссылки вместо указателей, но смешивание ссылок и указателей невероятно запутанно. Здесь использование возвращаемого типа - действительно самое интересное.

Если вам абсолютно необходимо использовать существующую подпись, вы можете быть хитрым и инициализировать список, тогда в функции init() вы можете сделать следующий переданный указатель списка указателем на список, который вы действительно хотите создать. Затем, после вызова init(), вы можете взять следующий указатель и удалить исходный объект списка, который вы создали. Или вы могли бы просто иметь первый элемент с помощью какого-то фиктивного элемента.

1 голос
/ 10 февраля 2011

это задание, вероятно, является хорошим способом обучения в классе передаче по значению и передаче по ссылке. Если вы хотите сохранить сигнатуру конструктора, вам нужно изменить основную функцию.

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

Теперь здесь список имеет тип List, а не адрес для List. Метод init () передал адрес списка, и внутри init вы можете изменить значение содержимого структуры.

. / A.out

длина финальная 3

0 голосов
/ 10 февраля 2011

init должен быть передан указатель на существующий список. Я подозреваю, что настоящая проблема здесь с вашей структурой данных. У вас есть нечто, называемое списком, которое содержит длину, но нигде не видно ни одного списка. Список, вероятно, должен содержать указатель на массив заданной длины, а init должен распределять этот массив и устанавливать указатель. Вы, вероятно, узнаете об этом, когда попросите профессора исправить свои требования, которые не нарушены - если бы они были, он, вероятно, услышал бы об этом от прошлых студентов и исправил бы их к настоящему времени.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...