Как вернуть правильный тип данных без предупреждений - PullRequest
0 голосов
/ 22 апреля 2020

Я пытаюсь построить свою собственную структуру данных связанного списка, и у меня возникают проблемы с одной вещью: я понятия не имею, возвращать ли тип данных struct, который работает как NULL с указателем. Например:

item pophead(node *list)
{
    head = list;
    node *newlist = (node *) malloc(sizeof(node*));
    item result;
    if(!list)
    {
        perror("There is nothing to be pop\n");
        return;
    }
    else
    {
        newlist = list->next;
        result = list->data;
        free(list);
        list = newlist;
    }
    return result;
}

Это моя программа для извлечения элемента из верхней части связанного списка. Проблема состоит в том, чтобы в первом случае проверить, является ли список пустым, поэтому я хочу, чтобы моя prgram ничего не возвращала, но когда я пишу так, появляется предупреждение.

Я хочу добавить это item здесь это тип данных структуры, а не один тип данных, например int или char.

Ответы [ 2 ]

1 голос
/ 22 апреля 2020

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

Если вы вернете указатель на заголовок node, то вы возьмете на себя ответственность за освобождение node. , Если вы вернете item в заголовке node, вам придется беспокоиться о том, чтобы освободить node.

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

Я собираюсь предположить, что вы хотите вернуть item, и что node можно освободить с помощью free. В этом случае мы можем вернуть 0 для успеха и -1 для неудачи, передать список по ссылке, а также передать указатель туда, куда вы хотите поместить всплывающий item (если есть).

int pophead(node **list, item *item)
{
    node *head = *list; // get a pointer to the head node

    if (head == NULL) {
        return -1; // list is empty; error
    }

    *item = head->data; // copy the data to the output
    *list = head->next; // update the list
    free(head);         // free the head element

    return 0; // success
}

Затем вы бы вызвали функцию следующим образом:

node *the_list = NULL;

// TODO: populate the_list somehow

item the_item;

if (pophead(&the_list, &the_item) == 0) {
    // process the_item
}

Кстати, в C ++ библиотека стандартных шаблонов определяет предварительное условие, что список должен быть непустым, так что всплывающее окно не может потерпеть поражение. Он предоставляет отдельную функцию для проверки того, что список не пустой, что вызывающая сторона должна проверить, прежде чем пытаться всплыть. Таким образом, элемент может быть возвращен по значению без необходимости возвращать индикатор ошибки.

В C, как правило, невозможно вернуть что-то, что может иметь любое значение или ошибку.

1 голос
/ 22 апреля 2020

Если вы не return newlist;, вам нужно будет передать адрес list, например, item pophead(node **list), чтобы вы могли использовать исходный указатель вместо копии. Почему? C - передача по значению, когда вы передаете переменную в качестве параметра, функция получает копию переменной. Любые изменения, которые вы делаете в своей функции, теряются при возврате.

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

item pophead(node **list)
{
    head = *list;
    // node *newlist = malloc(sizeof *newlist);  // (no allocation needed)
    node *newlist = NULL;
    item result;
    if(!*list)
    {
        perror("There is nothing to be pop\n");
        return;
    }
    else
    {
        newlist = head->next;
        result = head->data;
        free(head);
        *list = newlist;
    }
    return result;
}

( примечание: нет необходимости выделять для newlist, вы просто назначаете адрес из существующего узла указателю, не копируя содержимое в новое хранилище)

Тогда в вызывающей функции вместо вызова:

item someitem = pophead (list);

вы бы позвонили

item someitem = pophead (&list);

( note: In C, нет необходимости разыгрывать возврат malloc, это не нужно. См .: Я разыгрываю результат mallo c? )


Ничего не возвращается или struct item В зависимости от того, пуст ли список

Из нашего расширенного обсуждения, исходя из того, что я почерпнул из нашего разговора, вы говорите с item result;, если список пуст, вы бы хотели бы ничего не возвращать или иначе вы хотели бы вернуть result.

Вы объявили, что ваша функция возвращает тип item, и вы подтвердили, что item - это тип struct, а не typedef из указателя . Тип определяет, что вы можете вернуть. Когда вы объявляете, что ваша функция возвращает тип item - это то, что она должна возвращать. Если бы тип был item *, то у вас была бы возможность вернуть NULL (и пустой указатель) или указатель на выделенный блок, содержащий тип item.

Вы можете вернуть struct item инициализирует все нули в случае, если список пуст или структура полностью заполнена значениями, если в списке есть узлы. Где вы в настоящее время объявляете:

    item result;    /* which leaves the values indeterminate */

Вы можете инициализировать с помощью универсального инициализатора {0}, или предпочтительной инициализацией в C будет использование именованного инициализатора , где вы можете установить значение первого члена в ноль (или пустую строку в случае массива символов) и все остальные члены будут инициализироваться нулем по умолчанию, например,

    item result = {0};

Возвращая item инициализированный ноль или возврат item с членами, заполненными значениями, - это только два варианта вашей функции с типом возврата item. Вы не можете просто return;, как если бы вы делали тип возвращаемого значения void, поэтому вы либо меняете тип функции, либо возвращаете result, либо инициализируете все ноль или значениями.

...