Home > Blockchain >  Is there a way to re-write this using a double pointer (**)? [closed]
Is there a way to re-write this using a double pointer (**)? [closed]

Time:09-17

static entry_t *find_previous_entry_for_key(entry_t *first_entry, int key)
{
  entry_t *previous = first_entry; 
  entry_t *cursor = previous->next;
  while (cursor != NULL) 
  { 
    if (cursor -> key == key)
      {
        return previous;
      }
    cursor = cursor->next;
  }
  return previous;
}

Is there a way to re-write this using a double pointer? The struct for entry t looks like this:

struct entry
{
  int key;       // holds the key
  char *value;   // holds the value
  entry_t *next; // points to the next entry (possibly NULL)
};

CodePudding user response:

Is there a way to re-write this using a double pointer?

I take the question to be whether it is possible to return the result via an out parameter, which would need to be a double pointer because the value to be returned is a (single) pointer. Yes, of course that's possible:

static void find_previous_entry_for_key(entry_t *first_entry, int key,
    entry_t **result)
{
  entry_t *previous = first_entry; 
  // ...

  // return previous;
  *result = previous;
}

Then, instead of calling it like this:

// old way
entry_t *result = find_previous_entry_for_key(head, 42);

one would use

// new way
entry_t *result;
find_previous_entry_for_key(head, 42, &result);

CodePudding user response:

For starters the function is incorrect. It can invoke undefined behavior at least because there is no check whether the pointer first_entry is equal to NULL.

Also within the function the pointer previous is not being changed. So the function always returns the value of the passed to it pointer first_entry due to this assignment.

entry_t *previous = first_entry; 

So the function as it is written does not make a sense.

It seems that the function is designed to return a pointer to a pointer in the list that points to a node with the given value of the parameter key.

Using this function you will be able to insert a new node before the node with the given value of key or to remove a node from the list with the given value of key.

The function declaration and definition can look as shown in the demonstrative program below.

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

typedef struct entry entry_t;

struct entry
{
    int key;       // holds the key
    char *value;   // holds the value
    entry_t *next; // points to the next entry (possibly NULL)
};


void display( const entry_t *head )
{
    for ( ; head != NULL; head = head->next )
    {
        printf( "{ %d, %s } -> ", head->key, head->value );
    }
    
    puts( "null" );
}

static entry_t ** find_previous_entry_for_key( entry_t **first_entry, int key ) 
{
    while ( *first_entry != NULL && ( *first_entry )->key != key )
    {
        first_entry = &( *first_entry )->next;
    }

    return first_entry;
}

int main(void) 
{
    entry_t *head = NULL;
    
    int key = 1;
    char *value = "A";
    
    entry_t **target = find_previous_entry_for_key( &head, key );
    
    entry_t *new_entry = malloc( sizeof( entry_t ) );
    new_entry->key = key;
    new_entry->value = value;
    new_entry->next = *target;
    *target = new_entry;

    display( head );
    
    key = 3;
    value = "C";
    
    target = find_previous_entry_for_key( &head, key );
    
    new_entry = malloc( sizeof( entry_t ) );
    new_entry->key = key;
    new_entry->value = value;
    new_entry->next = *target;
    *target = new_entry;

    display( head );

    int new_key = 2;
    key = 3;
    value = "B";
    
    target = find_previous_entry_for_key( &head, key );
    
    new_entry = malloc( sizeof( entry_t ) );
    new_entry->key = new_key;
    new_entry->value = value;
    new_entry->next = *target;
    *target  = new_entry;

    display( head );
    
    key = 2;
    
    target = find_previous_entry_for_key( &head, key );
    
    
    if ( *target != NULL )
    {
        new_entry = *target;
        *target = ( *target )->next;
        free( new_entry );
    }

    display( head );
    
    key = 1;
    
    target = find_previous_entry_for_key( &head, key );
    
    
    if ( *target != NULL )
    {
        new_entry = *target;
        *target = ( *target )->next;
        free( new_entry );
    }

    display( head );
    
    key = 3;
    
    target = find_previous_entry_for_key( &head, key );
    
    
    if ( *target != NULL )
    {
        new_entry = *target;
        *target = ( *target )->next;
        free( new_entry );
    }

    display( head );
    
    return 0;
}

The program output is

{ 1, A } -> null
{ 1, A } -> { 3, C } -> null
{ 1, A } -> { 2, B } -> { 3, C } -> null
{ 1, A } -> { 3, C } -> null
{ 3, C } -> null
null

As you can see you are able to insert a node with key equal to 2 before the node with key equal to 3. Or you can remove the node before the node with key equal to 2 or the first node using the function.

CodePudding user response:

From smartphone, so I keep it terse.

Yes, in C it is the most elegant way to use an alias, a pointer to a variable.

Normally on has a node* head and you do

node** p = &head;
while (*p && (*p)->key != key) p = &(*p)->next;
*p = (*p)->next; // remove without free

p will point to (is an alias of) either head or a next field. Thus you can remove or insert nodes.

The code above assumes the key is found.

So a previous pointer is not needed as for instance in Java. A unique feature of C.

  • Related