Search code examples
cstructdynamic-memory-allocation

How to delete a value in a struct?


I am trying to delete a "user" from the struct on my code.

For example, this is the struct I have:

struct clients {
   char name[30];
   int year;
   float amount;
};

And this is the two outputs I have:

Name: Victor
Birth Year: 1998
Amount: 1000.00
Name: John
Birth Year: 1996
Amount: 1500.00

What I want to do is to delete John and all his information from my struct.

I am trying to learn dynamic memmory allocation, so I used this command:

clt = (struct clients*) malloc(n * sizeof(struct clients));

In my case I wish to write a command on case 3 that delete john from the struct, but I really can't figure out how to do that, I guess maybe using realloc? But I didn't even get close to write something it would work.

Here is my entire code so far:

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

struct clients {
    char name[30];
    int year;
    float amount;
};

int main() {
    struct clients *clt;
    int option, n, d = 0;
    char name[30];

    printf("Welcome, Choose an option to begin:");

    do {
        printf("\n1 - Create a new list;\n");
        printf("2 - Find a person in the list;\n");
        printf("3 - Delete a person from the list.\n");
        printf("4 - End the program.\n");
        scanf("%d", &option);

        switch (option) {
            case 1:
                printf("\nType how many clients you want to register:");
                scanf("%d", &n);

                // allocating memory for n numbers of struct person
                clt = (struct clients*) malloc(n * sizeof(struct clients));

                for (int i = 0; i < n; i++) {
                    printf("Type the name and the birth year:");
                    // To access members of 1st struct person,
                    scanf("%s %d", (clt + i)->name, &(clt + i)->year);

                    printf("\nType the amount:");
                    scanf("%f", &(clt + i)->amount);
                }

                break;
            case 2:
                printf("Type the name you want to find:");
                scanf("%s", name);

                for (int i = 0; i < n; i++) {
                    if (strcmp(&clt[i].name, name) == 0) {
                        printf("\nThats the name:");
                        printf("\nName: %s\n", (clt + i)->name);
                        printf("Birth Year: %d\n", (clt + i)->year);
                        printf("Amount: %.2f\n", (clt + i)->amount);
                        d++;
                    }
                }

                if (d == 0)
                    printf("This name doesn't exist\n");
    
                break;
            case 3:
                break;
            case 4:
                break;
        }
    } while (option != 4);

    return 0;
}

Solution

  • You need to discard the element from its location in the list by moving the contents in the remainder of the list up , and overwriting the target element.

    for(int i = 0; i < n; i++) {
    
        if (strcmp(&clt[i].name, name)==0)
        {
            printf("\nThats the name:");
    
            printf("\nName: %s\n", (clt+i)->name);
            printf("Birth Year: %d\n", (clt+i)->year);
            printf("Amount: %.2f\n", (clt+i)->amount);
            d++; // This seems to be your sentinel value?
        }
    
        if ( 1 == d && i+1 != n ) // if the sentinel is set, but we're not off the end of the list yet
        {
            memcpy(clt+i, clt+i+1, sizeof( struct clients )); 
        }
    }
    
    n--; // reduce the list length
    

    You could do this in one memmove call if you prefer. As @Neil says in the comments, memmove is tolerant of overlapping source and destination.

    if ( 1 == d && i != n-1 ) // if the sentinel is set, but we're not off the end of the list yet
    {
        memmove(clt+i, clt+i+1, (n-i-1) * sizeof( struct clients )); 
        break; // break for i
    }