Thread: Structs, dynamic memory, and phone book entries

  1. #1
    Registered User
    Join Date
    Oct 2009
    Posts
    3

    Structs, dynamic memory, and phone book entries

    I am working on the classic phone book program in a C programming course, and am having a bit of difficulty with the structs, pointers, and dynamic memory allocation. The program should dynamically allocate and free memory as it moves along (as the user adds or deletes entries). For now I am focusing mainly on case 1, which is add an entry to the phone book. Later, I will move the add, delete, and print functionality to functions, but am keeping everything inside main for simplicity until then.

    Can someone help me understand where I am going wrong in the add an entry part? When I run this code and examine the debug output, it seems there is an error writing to the memory address... so I assume I have an error in my pointers. Thanks for any help you can provide, I greatly appreciate it!

    Code:
    Description:
    A program utilizing data structures to create, manipulate, and display phone book entries.  User can add, delete, and print the phone book entries.
    */
    
    #include <stdio.h>     // Standard C input & output library
    #include <stdlib.h>    // mallac, callac, and free functions
    
    
    typedef struct PhoneBookEntry         // Declaration of phone book structure
    {
         char FirstName[21];
         char LastName[21];
         int PhoneNum;
    } person; 
    
    
    int main() {             // Main driving function
    
        int select=0; // Integer variable for user input of phone book operation
        int contact_ctr=0; // Counter to track number of contacts
        int i=0; // Index for printing "for" loop
        
        person contacts[50];   // Declare an array of phone book entries
        person* pcontacts;  // Declare a pointer for array Entries
    	//   pcontacts = &contacts[0];         // Initialize the pointer to the array's first position
        pcontacts = (person*) calloc(0, sizeof(person));    // Set pointer to allocated/initialized block of memory, size of person struct
        if (pcontacts == NULL)
           {printf("Out of memory!  Aborting...");
           return 1;}
        else  {}    // Do nothing!
    
        
        do {  // Print menu to screen, ask user for selection...
            printf("\nPhone Book Application:\n\n");
            printf("1) Add friend\n");
            printf("2) Delete friend\n");
            printf("3) Show phone book\n");
            printf("4) Exit\n");
            printf("What do you want to do? ");
            scanf("%d", &select);    // Store user input in variable "select"
            getchar();               // Clear the input buffer
       
            switch (select)
            {
                   case 1:     // User wants to add an entry
                        contact_ctr++;
                        pcontacts = realloc(pcontacts, contact_ctr * sizeof(person));     // Reallocate memory for additional contact
                        printf("\nFirst name: ");
                        scanf("%s", contacts[contact_ctr-1].FirstName);
                        printf("Last name: ");
                        scanf("%s", contacts[contact_ctr-1].LastName);
                        printf("Phone number: ");
                        scanf("%d", contacts[contact_ctr-1].PhoneNum);
                        printf("Record added to the phone book\n\n");
                        break;
                   case 2:    // User wants to delete an entry
                   case 3:    // User wants to print the phone book
                        for(i=0; i<contact_ctr; i++)
                        {
                                 printf("\n\nPhone Book Entries:\n\n");
                                 printf("%s %s %d", contacts[contact_ctr-1].FirstName, contacts[contact_ctr-1].LastName, contacts[contact_ctr-1].PhoneNum);
                        } // end for loop
                        break;
                   case 4:    // User wants to quit, break the switch and exit to loop
                        break;
                   default:   // User entered a value other than 1,2,3, or 4.
                        printf("You entered an invalid selection.  Try again.\n\n\n"); 
                        break;
            }  // End switch statement
            }  // End do loop
            
       while (select!=4);
       
       printf("\nThis phone book will now close.  Goodbye!\n");
       // Pause program until user inputs any character
       getchar();
       // Return statement
       return 0;
    }      // End main

  2. #2
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    Code:
    scanf("%d", contacts[contact_ctr-1].PhoneNum);
    When reading an integer with scanf(), you must pass the address of the int, not the int itself, so scanf() knows where to write (you always need to pass an address for scanf() to know where to write, but it happens automatically with arrays, so you don't see problems with %s). Use & to get the address of the int.

    Your compiler should be able to detect problems like this. If you're using gcc, always build with at least the -Wall option. Check your compiler's documentation for various diagnostic switches. And don't make the common mistake of thinking of warnings as being non-serious: often times (most of the time with gcc's -Wall flag) a warning points to a real problem in the code.

  3. #3
    Registered User datainjector's Avatar
    Join Date
    Mar 2002
    Posts
    356
    I once also did such a thing .. After having had enought pills .. i wasnt satified as being a normal human ..so instead of proving to my self that the medication which makes me a zombie .. might not be true ..

    i wrote this program ..so i could prove to myself i wasnt being brain washed by doctors for there money pills ..

    Address Book
    "I wish i could wish my wishs away"

    "By indirections find directions out" -- William Shakespears

    "Do what thou wilt shall be the whole of the law" -- Crowley "THE BEAST 666"

    Mizra -> love = Death...
    RDB(Rocks yooo)..

    http://www.cbeginnersunited.com

    Are you ready for the Trix ???

  4. #4
    Registered User
    Join Date
    Oct 2009
    Posts
    3
    Quote Originally Posted by cas View Post
    Code:
    scanf("%d", contacts[contact_ctr-1].PhoneNum);
    When reading an integer with scanf(), you must pass the address of the int, not the int itself, so scanf() knows where to write (you always need to pass an address for scanf() to know where to write, but it happens automatically with arrays, so you don't see problems with %s). Use & to get the address of the int.

    Your compiler should be able to detect problems like this. If you're using gcc, always build with at least the -Wall option. Check your compiler's documentation for various diagnostic switches. And don't make the common mistake of thinking of warnings as being non-serious: often times (most of the time with gcc's -Wall flag) a warning points to a real problem in the code.
    Thanks cas! I was so focused on directing the input into the correct array cell that I forgot about passing the actual address. I also turned on warnings in my compiler, so hopefully that will help me out some.

  5. #5
    Registered User
    Join Date
    Oct 2009
    Posts
    3
    After some more work, I finally ended up with a working phone book program. I have since moved the add, delete, and print entries functionality into separate functions, and now I have two new issues:

    1) A warning at compile time that states:
    Code:
    117 [Warning] passing arg 1 of `strcpy' makes pointer from integer without a cast
    and that line of code is inside the Del function:
    Code:
    strcpy(contacts[i].PhoneNum, nullStr);
    Phone Num is an int and nullStr is a char but so far I have been unsuccessful at typecasting this.

    2) The add and print functions appear to work correctly. When trying to delete an entry from the book, the program crashes. I assume I have some error in passing arguments and pointers to this function, since the delete worked before I broke the program into functions. Any suggestions?
    Code:
    /*
    Description:
    A program utilizing data structures to create, delete, and display phone book entries.
    User can add, delete, and print the phone book entries.
    */
    
    #include <stdio.h>     // Standard C input & output library
    #include <stdlib.h>    // mallac, callac, and free functions
    #include <string.h>		// String functions (string copy, string compare)
    
    
    typedef struct PhoneBookEntry         // Declaration of phone book structure
    {
         char FirstName[21];
         char LastName[21];
         int PhoneNum;
    } person; 
    
    // FUNCTION PROTOTYPES:
    void Add (int*, int, person*);	// Function to add an entry
    void Del (int*, int, person*);	// Function to delete an entry
    void Print (int*, int, person*);	// Function to print the phone book
    
    
    int main() {             // Main driving function
    
        int select=0; // Integer variable for user input of phone book operation
        int contact_ctr=0; // Counter to track number of contacts
        int i=0; // Index for printing "for" loop
    	
        
        person contacts[50];   // Declare an array of phone book entries
        person* pcontacts;  // Declare a pointer for array Entries
        pcontacts = (person*) calloc(0, sizeof(person));    // Set pointer to allocated/initialized block of memory, size of person struct
        if (pcontacts == NULL)
           {printf("Out of memory!  Aborting...");
           return 1;}
        else  {}    // Do nothing!
    
        
        do {  // Print menu to screen, ask user for selection...
            printf("\n\nPhone Book Application:\n\n");
            printf("1) Add friend\n");
            printf("2) Delete friend\n");
            printf("3) Show phone book\n");
            printf("4) Exit\n");
            printf("What do you want to do? ");
            scanf("%d", &select);    // Store user input in variable "select"
            getchar();               // Clear the input buffer
       
            switch (select)
            {
                   case 1:     // User wants to add an entry
    				    pcontacts = realloc(pcontacts, contact_ctr * sizeof(person));     // Reallocate memory for additional contact
    					Add (&contact_ctr, i, contacts);
                        break;
                   case 2:    // User wants to delete an entry
    					Del (&contact_ctr, i, contacts);
                        break;
                   case 3:    // User wants to print the phone book
    					Print (&contact_ctr, i, contacts);
    					break;
                   case 4:    // User wants to quit, break the switch and exit to loop
                        break;
                   default:   // User entered a value other than 1,2,3, or 4.
                        printf("You entered an invalid selection.  Try again.\n\n\n"); 
                        break;
            }  // End switch statement
            }  // End do loop
            
       while (select!=4);
       
       printf("\nThis phone book will now close.  Goodbye!\n");
       // Pause program until user inputs any character
       getchar();
       // Return statement
       return 0;
    }      // End main
    
    
    void Add (int *contact_ctr, int i, person *contacts)
    {
    	(*contact_ctr)++;
    	// Need to add realloc failsafe, if NULL
        printf("\nFirst name: ");
        scanf("%s", &contacts[*contact_ctr-1].FirstName);
        printf("Last name: ");
        scanf("%s",  &contacts[*contact_ctr-1].LastName);
        printf("Phone number (7-digit, no dash): ");
        scanf("%d",  &contacts[*contact_ctr-1].PhoneNum);
        printf("Record added to the phone book\n\n");
    }	// End function Add
    
    void Del (int *contact_ctr, int i, person *contacts)
    {
    	char delTempf[21];	// Temporary string for deletion of an entry - first name
    	char delTempl[21];	// Temporary string for deletion of any array - last name
    	char nullStr[21] = {"\0"};	// Null string for use in deleting entries
    
    	printf("\nFirst name: ");
    	scanf("%s", &delTempf);
        printf("Last name: ");
    	scanf("%s", &delTempl);
    	// compare strings, find entry or return entry not found
    	for (i=0; i<*contact_ctr; i++)
    	{
    		if (strcmp(delTempf, contacts[i].FirstName) == 0)
    		{
    			strcpy(contacts[i].FirstName, nullStr);
    			strcpy(contacts[i].LastName, nullStr);
    			strcpy(contacts[i].PhoneNum, nullStr);
    			free(&contacts[i]);
    			(*contact_ctr)--;	// Contact deleted, update the contact total counter
    			break;
    		}
    		else
    		{
    			printf("\nEntry not found.\n\n");				
    		}
    	}	// End for loop
    
        printf("Record deleted from the phone book\n\n");
    }	// End function Del
    
    void Print (int *contact_ctr, int i, person *contacts)
    {
    	char nullStr[21] = {"\0"};	// Null string
    	if (*contact_ctr > 0)	// If there are entries, print them
    	{
    		printf("\n\nPhone Book Entries:\n\n");
    		for(i=0; i<*contact_ctr; i++)
    		{
    			if (strcmp(nullStr, contacts[i].FirstName) != 0)	// If this index is NOT null, print it
    			{
    				printf("%s %s %d\n", contacts[i].FirstName, contacts[i].LastName, contacts[i].PhoneNum);
    			}
    			else {}	// Do nothing (skip this index because no entry exists)
    		} // end for loop
    	}
    	else	// Else the book is empty, tell the user
    	{
    		printf("\n\nThe phone book is currently empty.\n\n");
    	}
    }	// End function Print

  6. #6
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    I have been unsuccessful at typecasting this.
    When you're having problems, your first response should not be to cast. Casting is rarely the right thing to do. In the case here, you have an int. Why would you try to copy a string into it? Just set it to zero, or whatever value you think means empty for an int.

    As for the crash, you should always use a debugger. If it supports your platform, I'd recommend valgrind. As a start, though, you should absolutely never call free() on memory that wasn't allocated with malloc()/realloc()/calloc() (or other function your platform might provide, such as strdup()).

    Finally, when you're using scanf() with %s, don't add a & to your string. It's either totally wrong (if your string is a pointer), or technically wrong (if your string is an array). It will probably work with an array, but it's still not right.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Phone memory error
    By geek@02 in forum Tech Board
    Replies: 2
    Last Post: 08-07-2009, 01:32 AM
  2. a phone book program
    By mackieinva in forum C Programming
    Replies: 2
    Last Post: 09-19-2007, 06:31 AM
  3. Moral dillema
    By VirtualAce in forum A Brief History of Cprogramming.com
    Replies: 40
    Last Post: 08-22-2004, 03:23 PM
  4. Contest Results - May 27, 2002
    By ygfperson in forum A Brief History of Cprogramming.com
    Replies: 18
    Last Post: 06-18-2002, 01:27 PM
  5. Linked Lists
    By bigblack in forum C++ Programming
    Replies: 7
    Last Post: 02-05-2002, 05:21 PM

Tags for this Thread