Как вернуть или выйти из функции, если выполняются условия - PullRequest
0 голосов
/ 25 февраля 2019

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

Спасибо

typedef struct node{
    void *data;
    struct node *next,*prev,*head,*tail;
}Node;

typedef Node *List;

Node pop_node(List plist,long index){
    Node *pnode;
    pnode=direct_to_head(plist)->next;
    if(index>list_count(plist)){
        fprintf(stderr, "index out of link list scope.");
        return;
    }
    while (pnode->next!=NULL && index-->0) {
        pnode=pnode->next;
    }

    return free_node(pnode);
}

Ответы [ 5 ]

0 голосов
/ 26 февраля 2019

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

Вот и весь мой код списка двойных перекрестных ссылок:

//
//  double_linklist.c
//  tt
//
//  Created by tarrant on 2019/2/16.
//  Copyright © 2019 tarrant. All rights reserved.
//

#include "double_linklist.h"

static void c_free(void *p){
    free(p);
    p=NULL;
}

static Node *direct_to_index(List plist,long index){
    Node *pnode;
    unsigned int count = list_count(plist);
    if (labs(index) > count+2){
        fprintf(stderr, "index out of scope.");
        return NULL;
    }
    if (index >=0){
        if(plist->head==NULL){
            pnode=plist;
        }
        else
            pnode=plist->head;
        while (true){
            if(--index<0)
                break;
            else
                if (pnode->next!=NULL)
                    pnode=pnode->next;
                else{
                    fprintf(stderr, "invalid node %p.",pnode);
                    return NULL;
                }
        }
    }
    else{
        if(plist->tail==NULL){
            pnode=plist;
        }
        else
            pnode=plist->tail;
        while (true){
            if(++index>=0)
                break;
            else
                if (pnode->prev!=NULL)
                    pnode=pnode->prev;
                else{
                    fprintf(stderr, "invalid node %p.",pnode);
                    return NULL;
            }
        }
    }
     return pnode;
}

static Node *direct_to_head(List plist){
    return direct_to_index(plist, 0);
}

static Node *direct_to_tail(List plist){
    return direct_to_index(plist, -1);
}

void empty_list(List plist){
    Node *tmp,*current;
    plist=direct_to_head(plist);
    current=plist->next;
    while (current->next!=NULL) {
        if(current->data!=NULL){
            c_free(current->data);
        }
        tmp=current;
        current=current->next;
        c_free(tmp);
    }
    current->prev=plist;
    plist->next=current;
}

List init_list(void){
    Node *head,*tail;
    if((head = (Node *)calloc(1, sizeof(Node)))!=NULL){
        tail = (Node *)calloc(1, sizeof(Node));
        head->tail=tail;
        head->data=(unsigned int *)calloc(1, sizeof(unsigned int));
        head->next=tail;
        if(tail!=NULL){
            tail->prev=head;
            tail->data=NULL;
            tail->head=head;
            return head;
        }
    }
    fprintf(stderr, "No space in initing.");
    return NULL;
}


bool isempty_node(const Node *pnode){
    if(pnode->data==NULL)
        return true;
    return false;
}

bool free_node(Node *pnode){
    unsigned int *count;
    Node *next,*prev;
    if(pnode->next==NULL ||pnode->prev==NULL){
        fprintf(stderr, "You are empting head,tail or invaild node.");
        return false;
    }
    count=direct_to_head(pnode)->data;
    next=pnode->next;
    prev=pnode->prev;
    next->prev=prev;
    prev->next=next;
    c_free(pnode);
    c_free(pnode->data);
    --*count;
    return true;
}

void free_all_empty_nodes(List plist){
    Node *phead;
    unsigned int count=0;
    phead=direct_to_head(plist)->next;
    while (phead->next!=NULL) {
        if((phead->data==NULL)&&(free_node(phead)==false))
            fprintf(stderr, "error in empting index %d",count);
        phead=phead->next;
        count++;
    }
}

Node *pop_node(List plist,long index){
    Node *pnode,*next,*prev;
    if (index>=0)
        index++;
    else
        index--;
    pnode=direct_to_index(plist, index);
    next=pnode->next;
    prev=pnode->prev;
    pnode->head=NULL;
    pnode->tail=NULL;
    next->prev=prev;
    prev->next=next;
    return pnode;
}

unsigned int list_count(List plist){
    unsigned int *count;
    Node *phead;
    if(plist->head==NULL){
        phead=plist;
    }
    else
        phead=plist->head;
    count=phead->data;
    return *count;
}

void insert_list(const void *data,List plist,size_t size,long index){
    Node *tmp,*current;
    unsigned int *count;
    if(data==NULL){
        fprintf(stderr, "data is empty.");
        return;
    }
    tmp=(Node *)calloc(1, sizeof(Node));
    tmp->data=(void *)calloc(1, size);
    if(tmp==NULL||tmp->data==NULL){
        fprintf(stderr, "no space for allocation.\n");
        return;
    }
    memcpy(tmp->data,data,size);
    if (index<0)
        index--;
    current=direct_to_index(plist, index);
    tmp->next=current->next;
    current->next->prev=tmp;
    current->next=tmp;
    tmp->prev=current;
    tmp->head=direct_to_head(current);
    tmp->tail=direct_to_tail(current);
    count=direct_to_head(plist)->data;
    ++*count;
}

void append_list(const void *data,List plist,size_t size){
    insert_list(data,plist,size,-1);
}

bool modify_node(Node *node,const void *data,size_t size){
    if((data==NULL)||(node->prev==NULL)||(node->next)==NULL)
        return false;
    free(node->data);
    node->data=(void *)malloc(size);
    memcpy(node->data,data,size);
    return true;
}

bool modify_list(const void *data,List plist,long index,size_t size){
    Node *phead;
    if(data==NULL)
        return false;
    if (index>=0)
        index++;
    else
        index--;
    phead=direct_to_index(plist, index);
    return modify_node(phead,data,size);
}

void traverse_list(const List plist,void (*pfun)(void *pdata),int flag){
    Node *pnode;
    if(flag>=0){
        pnode=direct_to_head(plist)->next;
        while (pnode->next!=NULL) {
            (pfun)(pnode->data);
            pnode=pnode->next;
        }
    }
    else{
        pnode=direct_to_tail(plist)->prev;
        while (pnode->prev!=NULL) {
            (pfun)(pnode->data);
            pnode=pnode->prev;
        }
    }
}
0 голосов
/ 25 февраля 2019

Неплохо, но возможно было бы определить Node с помощью вида значения "Invalid-Node", и в случае, если нет узла, который нужно вернуть, просто верните узел "Invalid-Node".

const Node InvalidNode = {(void*)-1, 
  (struct node*)-1, (struct node*)-1, (struct node*)-1, (struct node*)-1
};

#define NODE_IS_INVALID(n) ( \
  ((n).data == InvalidNode.data) && \
  ((n).next == InvalidNode.next) && \
  ((n).prev == InvalidNode.prev) && \
  ((n).head == InvalidNode.head) && \
  ((n).tail == InvalidNode.tail) \
)

Затем измените свою функцию так:

Node pop_node(List plist,long index){
  Node *pnode;
  pnode=direct_to_head(plist)->next;
  if(index>list_count(plist)){
    fprintf(stderr, "index out of link list scope.");
    return InvalidNode;

    ...

И назовите это так:

Node n = pop_node(...);
if (NODE_IS_INVALID(n))
{
   /* handle error */
}
else
{
   /* use n here */
}
0 голосов
/ 25 февраля 2019

Я хочу выпрыгнуть или вернуть нулевое значение ... Я не знаю, сможет ли это сделать С.

Краткий ответ: Нет

Вы - как разработчик - решили, что функция pop_node должна возвращать объект типа Node (он же struct node).Это означает, что код должен всегда возвращать объект типа Node.C не позволяет вам внезапно вернуть другой тип.Следовательно, что-то вроде return NULL; не будет разрешено.

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

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

0 голосов
/ 25 февраля 2019

Если объявлено, что функция возвращает void (то есть ничего), она может только ничего не возвращать.Если объявлена ​​функция, возвращающая некоторый другой тип T, это все, что она может вернуть.

Рассмотрим:

  1. , возвращая указатель на тип Node (который может быть NULL)
  2. возвращает несколько значений (в виде структуры, содержащей их), одно из которых является флагом или кодом ошибки
  3. , возвращая 2-е значение через дополнительный указатель, данный функции (опять же, однофлаг / код)
  4. с использованием longjmp ()

Другой вариант варианта 1 заключается в определении специальной глобальной переменной типа Node с подходящим/ узнаваемое имя, например ErrorNode, и возвращаем на него указатель.Затем вызывающая сторона может сравнить возвращаемый указатель с &ErrorNode, чтобы определить состояние ошибки.На первый взгляд, это не кажется чем-то особенным, но если вам в конечном итоге понадобится распознать несколько различных состояний ошибки (хотя и не слишком много), вы можете определить несколько таких переменных (не слишком много, потому что вам нужно будет использовать if/elseвместо switch, чтобы их можно было различить).

0 голосов
/ 25 февраля 2019

Вы хотите перейти в функцию - взгляните на оператор goto.Оператор goto используется для перехода в любое место внутри функции.

goto lable;

label: Statement;

В вашем случае выведите ошибку и перейдите к оператору free_node.Ключевое слово return в C завершает функцию с кодом возврата.

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