I'm working on a struct array and I need to dynamically delete elements from the struct. I have the added dynamically but I've run into some issues with deleting. I've researched different methods and tried a few. I found that one from here works, in that it will delete the entry but then using the view function won't print out the new array and crashes. I think it needs to be sorted but when I add my sort function it crashes before returning to the menu. The other method I tried also deleted the element through the index value but when viewed just outputted a bunch a symbols. Here's what I have. I commented out the 2nd method I used to see if that one in the end is easier to modify to work. Any help in the right direction would be beneficial.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h> /* not required for unix */
#include <sys/stat.h>  /* stat */

struct person {
   char firstname[12];
   char lastname[12];
   char birthdate[11];
};

void view(struct person *p, int max);
void swap(struct person *a, struct person *b);
void psort(struct person *p, int hi);

int add(struct person *p, int max);   /* prompt for first, last, and bd (in main) */ 
int del(struct person *p, int max);                               /* prompt for index value (in main)         */

int main(void)
{
   struct stat st;
   char choice;
   FILE *f;
   char filename[80] = "p19.db";
   int i, n, max=5, size, done = 0;

   struct person *p, *t;

   struct person porig[5] = {{"Jack","Smith","1993-05-05"},{"Julie","Allen","1992-05-09"},
                             {"Cori","Murdock","1990-05-11"},{"Suzi","Hall","1980-04-30"},
                             {"Sami","Sundance","1972-05-05"} };

   char menu[] = "(v)iew (+)add (-)del (?)search (a)ge (s)ave (q)uit ?  ";

   f = fopen(filename,"wb");       /* write binary file */
   fwrite(porig,sizeof(struct person),max,f);
   fclose(f);

   if( stat(filename,&st)==0 )
   {
      if (st.st_mode & S_IFREG )
      {
         int i;
         f = fopen(filename,"rb"); /* read binary file  */
         size = st.st_size;
         t = p = (struct person *) malloc(size);
         if ( fread(p,1,size,f)==size )
         {
            max = size/(sizeof(struct person)); 
            //printf("BEFORE sort()\n");
            //view(p,max);
            //psort(p,max);         /* test psort()       */
            //printf("AFTER sort()\n");
            //view(p,max);
            //free(p);
         }
         else
            printf("Error in reading %s\n", filename);
      }
      else
         printf("%s is not a regular file\n",filename);
   } 
   else
      printf("Unable to open %s\n", filename);

   while ( !done )
   {
      printf("%s", menu);
      scanf("%s", &choice);
      switch(choice)
      {
         case 'v': view(p,max);        break;
         case '+': 
         //struct person *t = p;
         p = add(p,max);
         if ( p==t )
             ;
         else
             max = max + 1;
         break;
         case '-': 
            p = del(p,i);
            if(p==t)
            {
               ;
            }   
            else
            {
               max = max - 1;
            }
            //psort(p,max);   
         break;
         case 'q': done = 1;           break;
         default: printf("Invalid choice.\n");
      }
   }
   printf("Done.\n");



   getchar();
   getchar(); /* system pause hack */
   return 0;
}
void view(struct person *p, int max)
{
   int i=0;
   struct person *t = p; 
   for(i=0;i<max;i++,t++)
      printf("[%d]%13s%13s%11s\n", i, t->firstname, t->lastname, t->birthdate);
}
void swap(struct person *a, struct person *b)
{
   struct person tempa = *a;
   *a = *b;
   *b = tempa;
}
int indexOfMin(struct person *p, int hi)
{
   int i, mindex = 0;
   for(i=1;i<hi;i++)
   {
      if ( strcmp((p+i)->lastname,(p+mindex)->lastname )< 0 )
         mindex = i;
      else
         ;
   }
   return mindex;
}
void psort(struct person *p, int hi)
{
   int i;
   struct person *t = p;
   for(i=0;i<hi-1;i++,t++) {
      swap(t,t+indexOfMin(t,hi-i));
   }
}
int add(struct person *p, int max)
{
     int i;
     struct person *t = NULL, *t0 = NULL, *p0 = p;
     t = t0 = (struct person*)malloc(sizeof(struct person)*(max+1));

     if ( t!=NULL )
     {
        for(i=0;i<max;i++)
            *t++ = *p++;
        printf("Enter a firstname, lastname and birthday (yyyy-mm-dd): ");
        if ( scanf("%s%s%s", &t->firstname, &t->lastname, &t->birthdate)==3)
        {
            if ( p0==NULL )
                ;
            else
                free(p0);
            p = t0;
        }
        else
            p = p0;
     }
     else
        fprintf(stderr,"Error, unable to malloc\n");
    return add;
}
int del(struct person *p, int max)
{
    int i = 0;
    char deleteFirstname[12];  // Temp string to compare to existing array
    char deleteLastname[12];  //temp string
    char nullStr[11] = {"\0"};  // empty string to remove birthdate
    printf("\nEnter firstname: ");
    scanf("%s", deleteFirstname); //place into temp string
    printf("Enter lastname: ");
    scanf("%s", deleteLastname); //place into temp string
    for (i = 0; i < max; i++)
    {
        if (strcmp(deleteFirstname, p[i].firstname) == 0) //compare deleteName to p.firstname
        {
            for (i = 0; i< max; i++)
            {
                if (strcmp(deleteLastname, p[i].lastname) == 0) //If deleteSurname matches p.lastname
                {
                    strcpy(p[i].firstname, nullStr); //Put null into firstname
                    strcpy(p[i].lastname, nullStr); //Null into lastname
                    strcpy(p[i].birthdate, nullStr); //Null into birthdate
                    printf("Person removed from array.\n");
                    i--;
                }
            }
        }
        else printf("Invalid entry--try again.\n");
    }


    //int i, a;
    //printf("Enter index value: ");
    //scanf("%d", &i);
    //if (i >= max+1)
    //{
       //printf("Deletion not possible.\n");
    //}
    //else
    //{
       //for ( a = i - 1 ; a < max - 1 ; a++ )
          //p[a] = p[a+1];
    //}
    return del;

}

line 76: I don't see where pointer p was ever initialized. That means function add() is getting an invalid pointer parameter.

Maybe you need to rethink how add() is supposed to work. IMHO add() should increase the array size by 1 each time it is called, and the first parameter should be a pointer to a pointer, so line 139 should be

int main()
{
    struct person* p = NULL;
    int max = 0;
    // now add a member to the array
    add(struct person &p, &max);
}


void add(struct person **p, int* max)
{
    *p = realloc(p,(*max+1) * sizeof(struct person));
    (*max)++; 
}

I think your delete function is also coded wrong, you don't need two loops. Check for both first and last names in the same loop.

Edited 3 Years Ago by Ancient Dragon

I do get that error for the add function when it complies but it would still add a new person with no issue so I had left it to move on. I know bad coding and bad practice. I will check out your suggestion and play with it so that error is gone.

As for the delete function I'm not surprised it's coded wrong. It's my first attempt at doing something like this so I'm learning. I'll combine them into one loop, but that still leaves my problem of the array not printing out after the element has been deleted. Should I add the print statement in the delete function instead of relying on the view function to print the array?

First off, since you are manipulating them together, it may be a good idea to bundle the array and max together, along with the current size:

struct people
{
    struct person** data;
    int size, max;
};

It is almost always better to separate the functions which manipulate data from the input and output functions, so I would keep view() and del() separate. Similarly, I would separate the add() and del() functions from the function to resize the array, as so:

struct person** resize(struct people p, int new_max)
{
    p->data = realloc(p->data, new_max * sizeof(struct person));
    p->max = new_max;

    return p->data;
}

struct person* add(struct people p, char* firstname, char* lastname, char* birthdate)
{
    struct* person new_person;

    p->size++;

    if (p->size >= p->max)
    {
        // if the current size is equal to or greater than
        // the total size of the array, double the size of the array
        result = resize(p, p->max * 2);
        if (result == NULL)
        {
            return NULL;  // could not allocate additional space
        }
    }

    new_person = p->data[size - 1];
    new_person->firstname = firstname;
    new_person->lastname = lastname;
    new_person->birthdate = birthdate;

    return new_person;
}

This approach is not only more efficient than resizing every time the size changes, it separates the three sets of concerns (inputting the new person, adding the new person to the array, and managing the size of the array) so as to make it more modular and easier to understand.

This article has been dead for over six months. Start a new discussion instead.