Thread: understanding double pointers in functions and linked lists

  1. #1
    Registered User
    Join Date
    May 2006
    Posts
    182

    understanding double pointers in functions and linked lists

    My book gives an example of a linked list algorithm. To test my understanding I memorized the logic of "insert" and rewrote it. It looked the same except for one thing. The book example has a double pointer parameter, whereas mine used only a single pointer. My insert didn't work until I modified it to also use two points of indirection. I think I figured out why but I want you guys to confirm or deny.

    When I use a single point of indirection and pass the value in a pointer variable it is being passed call by value. When I use a double pointer I get to use the address operator (&) to pass the pointer which tells the compiler it is to be passed call by reference.

    If this is the case, it sure wasn't mentioned in the book! Does a primitive type only get passed call by reference when it has the address operator input in the function argument?



    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    
    struct listNode {
    	char data;
    	struct listNode *nextPtr;
    };
    
    typedef struct listNode ListNode;
    typedef ListNode *ListNodePtr;
    /*  Does this mean any structure declared using ListNodePtr
        will automatically be a pointer without using the * cast?  */
    
    //void insert( ListNodePtr *, char );
    void insert( ListNode **sPtr, char value );
    char delete( ListNodePtr *, char );
    int isEmpty( ListNodePtr );
    void printList( ListNodePtr );
    void instructions( void );
    
    int main()
    {
    	ListNode *startPtr = NULL;
    	int choice;
    	char item;
    
    	instructions();
    	printf( "? " );
    	scanf( "%d", &choice );
    
    	while( choice != 3 ) {
    
    		switch( choice ) {
    			case 1:
    				printf( "Enter a character: " );
    				scanf( "\n%c", &item );
    				/*  startPtr is a pointer.  What does it mean to use the address operator on a pointer?  */
    				insert( &startPtr, item );
    				printList( startPtr );
    				break;
    
    			case 2:
    				if ( !isEmpty( startPtr ) ) {
    					printf( "Enter character to be deleted: " );
    					scanf( "\n%c", &item );
    
    					if ( delete( &startPtr, item ) ) {
    						printf( "%c deleted.\n", item );
    						printList( startPtr );
    					}
    					else
    						printf( "%c not found.\n\n", item );
    				}
    				else
    					printf( "List is empty.\n\n" );
    
    				break;
    			default:
    				printf( "Invalid choice.\n\n" );
    				instructions();
    				break;
    		}
    		printf( "? " );
    		scanf( "%d", &choice );
    	}
    
    	printf( "%c\n", startPtr->data );
    	printf( "End of run.\n" );
    	return 0;
    }
    
    
    void insert( ListNode **sPtr, char value )
    {
    	ListNode *newPtr, *previousPtr, *currentPtr;
    
    	newPtr = malloc( sizeof( ListNode ) );
    
    	if ( newPtr != NULL ) {
    		newPtr->data = value;
    		newPtr->nextPtr = NULL;
    
    		currentPtr = *sPtr;
    		previousPtr = NULL;
    
    		while ( currentPtr != NULL && value > currentPtr->data ) {
    			previousPtr = currentPtr;
    			currentPtr = currentPtr->nextPtr;
    		}
    		if ( previousPtr == NULL ) {
    			newPtr->nextPtr = *sPtr;
    			*sPtr = newPtr;
    		}
    		else {
    			previousPtr->nextPtr = newPtr;
    			newPtr->nextPtr = currentPtr;
    		}
    	}
    
    }
    
    
    void instructions( void )
    {
    	printf( "Enter your choice:\n"
    		   "   1 to insert an element into the lsit.\n"
    		   "   2 to delete an element from the list.\n"
    		   "   3 to end.\n" );
    }
    
    
    /*
    void insert( ListNode *sPtr, char value )
    {
    	ListNodePtr newPtr, previousPtr, currentPtr;
    
    	newPtr = malloc( sizeof( ListNode ) );
    
    	if ( newPtr != NULL ) {
    		//  data is not a pointer, why is the -> used to access it then?  
    		newPtr->data = value;
    		newPtr->nextPtr = NULL;
    
    		previousPtr = NULL;
    		currentPtr = sPtr;
    //		Is currentPtr pointing to the value at sPtr or the address of sPtr?  
    
    		while ( currentPtr != NULL && value > currentPtr->data ) {
    			previousPtr = currentPtr;
    			currentPtr = currentPtr->nextPtr;
    		}
    
    		if ( previousPtr == NULL ) {
    			newPtr->nextPtr = sPtr;
    			sPtr = newPtr;
    		}
    		else {
    			previousPtr->nextPtr = newPtr;
    			newPtr->nextPtr = currentPtr;
    		}
    	}
    	else
    		printf( "%c not inserted. No memory available.\n", value );
    }
    */
    
    char delete( ListNodePtr *sPtr, char value )
    {
    	ListNodePtr previousPtr, currentPtr, tempPtr;
    
    	/*  Does this mean the value of a struct name is the memory address?  */
    	/*  Could I use a non-pointer struct and change the mem address it points to?  */
    	if ( value == ( *sPtr )->data ) {
    		tempPtr = *sPtr;
    		*sPtr = ( *sPtr )->nextPtr;
    		free( tempPtr );
    		return value;
    	}
    	else {
    		previousPtr = *sPtr;
    		currentPtr = ( *sPtr )->nextPtr;
    
    		while ( currentPtr != NULL && currentPtr->data != value ) {
    			previousPtr = currentPtr;
    			currentPtr = currentPtr->nextPtr;
    		}
    
    		if ( currentPtr != NULL ) {
    			tempPtr = currentPtr;
    			previousPtr->nextPtr = currentPtr->nextPtr;
    			free( tempPtr );
    			return value;
    		}
    	}
    
    	return '\0';
    }
    
    
    int isEmpty( ListNodePtr sPtr )
    {
    	return sPtr == NULL;
    }
    
    
    void printList( ListNodePtr currentPtr )
    {
    	if ( currentPtr == NULL )
    		printf( "List is empty.\n\n" );
    	else {
    		printf( "The list is:\n" );
    
    		while ( currentPtr != NULL ) {
    			printf( "%c --> ", currentPtr->data );
    			currentPtr = currentPtr->nextPtr;
    		}
    
    		printf( "NULL\n\n" );
    	}
    }

  2. #2
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Everything is always passed by value. You are passing the address of startPtr by value. Of course, that means that since you have an address, you can write to that address, so you can change the contents of startPtr.

  3. #3
    Registered User
    Join Date
    May 2006
    Posts
    182
    Thanks that clears some questions up.

  4. #4
    Registered User
    Join Date
    May 2006
    Posts
    182
    Is the name of a structure without any accessor operators a pointer to the structure?

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by yougene
    Is the name of a structure without any accessor operators a pointer to the structure?
    No. If I guess your line of thought correctly, unlike an array, a structure does not decay to a pointer when passed as an argument to a function. You have to pass the address of the structure explicitly.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #6
    Registered User
    Join Date
    May 2006
    Posts
    182
    Ahh I see.
    But if I declare a pointer to a struct and point it to an existing struct I don't have to use the (*) operator either.

    Code:
    struct blah *apointer;
    struct blah structure;
    
    apointer = &structure;
    
    //no * required here
    apointer.member;
    Is this syntactical sugar or does this represent something about what structures are?

  7. #7
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Except apointer.member is syntactically invalid. You have to use apointer->member instead.

  8. #8
    Registered User
    Join Date
    May 2006
    Posts
    182
    Don't you also use -> if member is a pointer and "apointer" isn't?
    The use of -> is where my question originally arose from.

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by yougene
    Don't you also use -> if member is a pointer and "apointer" isn't?
    No, you don't. a->b is syntactic sugar for (*a).b so it has nothing to do with whether b is a pointer.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  10. #10
    Registered User
    Join Date
    May 2006
    Posts
    182
    Gotchya thanks

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Linked Lists 101
    By The Brain in forum C++ Programming
    Replies: 5
    Last Post: 07-24-2004, 04:32 PM
  2. Passing pointers between functions
    By heygirls_uk in forum C Programming
    Replies: 5
    Last Post: 01-09-2004, 06:58 PM
  3. Request for comments
    By Prelude in forum A Brief History of Cprogramming.com
    Replies: 15
    Last Post: 01-02-2004, 10:33 AM
  4. One more question about linked lists?
    By shaeng in forum C Programming
    Replies: 2
    Last Post: 06-24-2003, 07:36 AM
  5. Linked lists
    By sballew in forum C Programming
    Replies: 6
    Last Post: 10-24-2001, 08:52 PM