Удаление всех записей структуры в программировании на C

#c #function #structure

#c #функция #структура

Вопрос:

У меня возникли проблемы с удалением всех записей в определенной структуре. Вот код функции для удаления одной записи и моя попытка выполнить функцию «удалить все»

 typedef struct person               //Structure Set up
{
    char fname[20];
    char lname[20];
    char number[20];
} person;

void delInfo(int num_entries,person*contacts)
{
    char delfirst[20];      //Setting up Arrays to match entry
    char dellast[20];
    printf("n First Name: ");
    scanf("%s",delfirst);
    printf(" Last Name: ");
    scanf("%s",dellast);
    int i=0;
    for (i=0; i<num_entries; i  )       //Going through contacts
    {
        if (strcmp(delfirst,contacts[i].fname)==0 amp;amp; strcmp(dellast,contacts[i].lname)==0)      //Testing for match between entry and contacts
        {
            for (i=i; i<num_entries-1; i  )         //Shifting every contact AFTER match down one
            {
                contacts[i]=contacts[i 1];
            }
            if(num_entries !=0)
                contacts=(person*)realloc(contacts,sizeof(person)*(num_entries-1)); //Freeing memory at end by way of realloc
            printf("n %s %s deleted from contactsnn",delfirst,dellast);
            break;
        }
    }
    if(i == num_entries)
    {
        printf("n Entry Not Foundn");
    }
    system("pause");
}

void deleteall(int num_entries,person*contacts)         //deleting all function
{
int i,j;
    for(i=0;i<num_entries;i  ){
        contacts[i].fname=NULL;
    contacts[i].lname=NULL;
        contacts[i].number=NULL;
    }
free(contacts);

    printf("n All contacts deletednn");
    system("pause");
}
  

Проблема в том, что это несовместимые типы (попытка присвоить array из void). Могу ли я просто использовать какой-нибудь цикл и использовать realloc для сокращения массива до 0? Я не уверен, как просто очистить все записи.

Ответ №1:

Элементы struct person имеют фиксированный размер и не выделяются отдельно от struct экземпляра. Короткий ответ заключается в том, что вы не можете изменять размер массивов или освобождать их хранилище без освобождения всего struct экземпляра. Самое лучшее, что вы можете сделать в этом случае, это написать пустую строку для каждого элемента, чтобы указать, что он не используется:

 strcpy( contacts[i].fname, "" );
  

Однако это не изменяет размер массива.

Чтобы сделать элементы struct person изменяемыми по размеру и / или удаляемыми, вы должны выделить их отдельно от самого struct экземпляра. Для этого вам нужно объявить их как указатели на char , в отличие от массивов char :

 struct person
{
  char *fname;
  char *lname;
  char *number;
};
  

При создании нового экземпляра struct person вам нужно будет выделить память для каждого элемента отдельно:

 #define SIZE 20  // for this example, both number of contacts and size
                 // of each struct member

struct person contacts[size];
for ( size_t i = 0; i < j; i   )
{
  contacts[i].fname = malloc( sizeof *contacts[i].fname * SIZE );
  contacts[i].lname = malloc( sizeof *contacts[i].lname * SIZE );
  contacts[i].number= malloc( sizeof *contacts[i].number * SIZE );
}
  

Чтобы изменить размер любого из элементов, используйте realloc :

  char *tmp = realloc( contacts[i].fname, sizeof *contacts[i].fname * SIZE * 2 );
 if ( tmp ) contacts[i].fname = tmp;
  

Поскольку realloc потенциально может произойти возврат NULL , рекомендуется сохранить результат во временной переменной указателя, а не сразу переназначать его обратно вашему исходному указателю; в противном случае вы рискуете потерять отслеживание ранее выделенной памяти, что приведет к утечке памяти.

Вы также захотите отслеживать, сколько памяти выделено для каждого элемента, чтобы избежать переполнения буфера.

Чтобы удалить любой из элементов, используйте free :

 free( contacts[i].fname );
  

Обратите внимание, что если вы динамически выделяете экземпляр struct person , вам все равно нужно динамически выделять каждый элемент:

 struct person *p = malloc( sizeof *p );
p->fname = malloc( sizeof *p->fname * SIZE );
...
  

Это также означает, что вы должны освободить каждый элемент перед освобождением самого экземпляра struct:

 free( p->fname );
free( p->lname );
free( p->number );
free( p );
  

Простое освобождение p не освободит память, выделенную для p->fname , p->lname и p->number .

Комментарии:

1. Можете ли вы пояснить, почему я должен использовать указатель на char вместо массива char для освобождения / удаления?

2. @NLhere: потому что мы динамически выделяем память с помощью malloc , которая всегда возвращает значение указателя.

Ответ №2:

Вам не нужно удалять три поля структуры, поскольку все они статически распределены по 20 байт каждое. Вам нужно освободить память только в пределах трех полей, если они динамически выделяются с помощью malloc.

Тем не менее, вам нужно освободить все динамически выделяемые контакты.

 void deleteall(int num_entries,person*contacts)         //deleting all function
{
    for(int i=0;i<num_entries;i  ){
        free(contacts  )
    }

    printf("n All contacts deletednn");
    system("pause");
}
  

Комментарии:

1. это приводит к [ошибке] несовместимому типу для аргумента 1 ‘free’ и [Примечание] ожидаемому ‘void *’, но аргумент имеет тип ‘person’

2. когда я пытаюсь запустить эту функцию, она теперь «перестает работать» и возвращает большое число

3. Тогда вам нужно предоставить больше информации. Есть ли ошибка сегментации? Как распределяются контакты до вызова этой функции? Находятся ли они в последовательной памяти или в спорадической?

4. @SimonBlack вы не можете освободить () отдельные элементы массива contacts, потому что весь массив, вероятно, был выделен malloc или calloc. Это не массив указателей.

5. @SimonBlack person* контакты; int num_entries=0; contacts = NULL;

Ответ №3:

Вы не можете присвоить NULL контактам[i].fname или contacts[i].lname, потому что это массивы, а NULL — значение указателя. Либо используйте что-то вроде memset(), либо просто ничего не делайте со структурой перед освобождением.