Home > database >  How to delete a value in a struct?
How to delete a value in a struct?

Time:09-26

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 ammount;
};

And this is the two outputs I have:

Name: Victor
Birth Year: 1998
Ammount: 1000.00
Name: John
Birth Year: 1996
Ammount: 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 ammount;
};

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 ammount:");
                    scanf("%f", &(clt   i)->ammount);
                }

                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("Ammount: %.2f\n", (clt   i)->ammount);
                        d  ;
                    }
                }

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

    return 0;
}

CodePudding user response:

You are describing almost a dynamic array such as C 's std::vector. It is static, but it could be a dynamic array without that much extra work. You could create a container, and split n into the container's capacity and size.

struct clients_array {
    size_t size, capacity;
    struct clients *data;
};

Instead of having multiple pointers, one could create a struct clients_array for each list. Sample code to deal with the struct clients_array.

#include <inttypes.h>
#include <assert.h>
#include <errno.h>

/** `a` constructor with `n` spots. Returns true or false depending on whether
 it could be constructed. */
static int clients_array_reserve(struct clients_array *const a,
    const size_t n) {
    assert(a && n);
    if(n > SIZE_MAX / sizeof *a->data) return errno = ERANGE, 0;
    if(!(a->data = malloc(sizeof *a->data * n))) return 0;
    a->capacity = n;
    a->size = 0;
    return 1;
}

/** `a` destructor; call this when `a` has been successfully constructed. */
static void clients_array_(struct clients_array *const a)
    { if(a) { free(a->data); a->data = 0; a->capacity = a->size = 0; } }

/** Extract a new uninitialized entry out of constructed `a`. Returns null if
 there is no more space. */
static struct clients *clients_array_new(struct clients_array *const a) {
    assert(a);
    return a->capacity > a->size ? a->data   a->size   : 0;
}

/** Remove index `rm` from `a`. */
static void clients_array_delete(struct clients_array *const a,
    const size_t rm) {
    assert(a && rm < a->size);
    memmove(a->data   rm, a->data   rm   1,
        sizeof *a->data * (a->size - rm - 1));
    a->size--;
}

Then one can have different, independent arrays at once. If you want to update the code, say to allow realloc to increase the size of the object, you only need to modify the container.

CodePudding user response:

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("Ammount: %.2f\n", (clt i)->ammount);
        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
}
  • Related