简体   繁体   中英

Declaring functions as variables in c

I'm currently reviewing for an exam at my university and came across some puzzling code examples with regards to linked list. In the book THE ALGORITHM DESIGN MANUAL by Steven S. Skiena, he uses some interesting syntax that I don't quite understand.

delete_list (list **l, item_type x)
{
    list *p;
    list *pred;
    list *search_list(), *predicessor_list();

    p = seach_list(*l, x);
    if (p != NULL)
    {
       pred = predecessor_list(*l, x);
       if (pred == NULL)
           *l = p-> next;
       else 
           pred->next = p->next;

       free (p);
    }

}

Is there a specific advantage or reason to declare the search_list() and predicessor_list() function rather than explicitly calling them? I am assuming that it has something to do with maintaining pointers but I cannot find any reference material on this.

These are function declarations. There are two things I'd consider bad about them:

  1. They lack a prototype:

     list *search_list(list *, item_type), *predecessor_list(list *, item_type); 

    The prototype (here list *, item_type for each function) tells the compiler what type of arguments (and how many of them) the function expects. There is no reason not to provide that information in a function declaration.

    If you just say list *search_list() , the compiler cannot check whether calls of search_list pass correct arguments.

  2. They are inside a function.

    There is no point in declaring a function inside a block. That doesn't make the function local; in standard C all functions are global. It just makes that declaration have local scope, which is fairly useless.

A more standard approach would be

list *search_list(list *, item_type);
list *predecessor_list(list *, item_type);

void delete_list (list **l, item_type x)
{
    ...
}

Note that I added a void return type since delete_list doesn't return any value. Omitting the return type used to be allowed in pre-1999 C, but it would default to int , not void .

Given that function prototypes became standard with the publication of ANSI C in 1989 and "implicit int " was removed in 1999 (with ISO 9899:1999), I'd be wary of the technical content in The Algorithm Design Manual (which bears a 2008 copyright notice).

They are certainly declared somewhere.. Example:

#include <stdio.h>
#include <stdlib.h>

typedef struct list {

} list;

void foo() {
    //Forward Declaration:
    list* search_list(), *predecessor_list();

    //Function call:
    list* search_results = search_list(/*whatever arguments here*/);
    list* predecessor_results = predecessor_list(/*whatever arguments here*/);

    //Printing Pointers or whatever..
    printf("%p\n", search_results);
    printf("%p\n", predecessor_results);
}

list* search_list(/*whatever arguments here*/) {
    return NULL; //return a list pointer or node..
}

list* predecessor_list(/*whatever arguments here*/) {
    return NULL; //return a list pointer or node..
}

int main() {
    foo();
    return 0;
}

If you comment out:

/*list* search_list() {
    return malloc(sizeof(list));
}

list* predecessor_list() {
    return malloc(sizeof(list));
}*/

You will get the error:

/usr/bin/ld: /home/J3v1L7/cc02GJDL.o: in function foo': prog.c:(.text+0x9): undefined reference to search_list' /usr/bin/ld: prog.c:(.text+0x13): undefined reference to `predecessor_list' collect2: error: ld returned 1 exit status

Why? Because list* search_list(), *predecessor_list(); is a forward declaration of the two functions search_list and predecessor : https://en.wikipedia.org/wiki/Forward_declaration

list *search_list(), *predicessor_list(); is a local declaration for 2 functions taking an unspecified number of arguments and returning a pointer to list whatever that might be.

Declaring functions in a block scope is highly discouraged. Declaring functions without a proper prototype is sloppy too. Defining delete_list without a return type is obsolete as well.

From the code posted, it seems the book is outdated and provides bad advice for newbies.

The proper code should be:

#include <stdlib.h>

typedef int item_type;

typedef struct list {
    item_type value;
    struct list *next;
} list;

list *search_list(list *l, item_type x);
list *predecessor_list(list *l, item_type x);

void delete_list(list **l, item_type x) {
    list *p;
    list *pred;

    p = search_list(*l, x);
    if (p != NULL) {
        pred = predecessor_list(*l, x);
        if (pred == NULL)
            *l = p->next;
        else 
            pred->next = p->next;
        free (p);
    }
}

And of course a better version of delete_list would avoid a double scan:

#include <stdlib.h>

/* delete the first node with value x, return 1 if found, else return 0 */
int delete_list(list **pp, item_type x) {
    for (list *p = *pp; p != NULL; pp = &p->next, p = p->next) {
        if (p->value == x) {
            *pp = p->next;
            free(p);
            return 1;
        }
    }
    return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM