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:
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.
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.