#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(), либо просто ничего не делайте со структурой перед освобождением.