满足条件时如何返回或退出功能

时间:2019-02-25 08:38:38

标签: c

我是C语言的新手,正在尝试为C语言编写一个双链表。如果要算出链表中的索引数但不退出整个程序,我想跳出或返回空值。仅用于打印错误并返回Null或用户会识别出超出范围的内容。我不知道C是否可以做到。 这是我的代码的一部分。 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 :(得分:1)

  

我想跳出或返回空值...我不知道C是否可以做到。

简短的回答是

您-作为设计人员-决定函数pop_node返回类型为Node(也称为struct node)的对象。这意味着代码应始终返回类型为Node的对象。 C不允许您突然返回另一种类型。因此,将不允许使用return NULL;之类的内容。

  

我只想知道该怎么处理这个弹出功能,以解决超出范围的问题。

您可以更改函数签名以返回指向Node的指针,并将复制/释放留给调用方。在这种情况下,您可以将NULL用作指示“无对象可用”的值。

答案 1 :(得分:0)

如果声明一个函数返回void(即什么也没有),则它只能返回什么。如果声明一个函数返回其他类型的T,那么它就可以返回所有内容。

考虑:

  1. 返回类型为Node(可以为NULL)的指针
  2. 返回多个值(作为包含它们的结构),其中一个是标志或错误代码
  3. 通过赋予该函数的另一个指针返回第二个值(同样,一个是标志/代码)
  4. 使用longjmp()

选项1的另一个变体是定义类型为Node的特殊全局变量,并使用合适/可识别的名称,例如ErrorNode,并返回指向它的指针。然后,调用者可以将返回的指针与&ErrorNode进行比较以检测错误情况。乍一看似乎并不特殊,但是如果您最终需要识别几个不同的错误情况(虽然不是太多),则可以定义多个这样的变量(不要太多,因为您需要使用{{1 }}而不是if/else来区分它们。

答案 2 :(得分:0)

不好,但可能会用{Invalid-Node“值定义一个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 */
}

答案 3 :(得分:0)

我已经改变了我的功能。我想我不需要将指针返回到节点,我只需要它的数据。这样我就可以在获取数据的同时释放节点。

这是我的整个双交叉链接列表代码:

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

答案 4 :(得分:-2)

您想在函数内跳转-看一下goto语句。 goto语句用于在函数内的任何位置跳转。

转到标签;

标签:      声明;

在您的情况下,打印错误并跳转至free_node语句。 C中的return关键字退出并返回代码。