Как работать со строковыми полями в C-структуре?
У меня возникли проблемы с созданием базы данных на основе односвязного списка на C, а не из-за концепции связанного списка, а скорее с строковыми полями в самой структуре.
Это назначение в C, и насколько я знаю (я новичок), C не распознает "string" как тип данных.
Вот как выглядит мой код структуры:
typedef struct
{
int number;
string name;
string address;
string birthdate;
char gender;
} patient;
typedef struct llist
{
patient num;
struct llist *next;
} list;
Я думал о создании структуры для самих строк, чтобы я мог использовать их в структуре, например:
typedef struct string
{
char *text;
} *string;
Тогда я буду malloc()
каждый из них, когда потребуется создавать новые данные типа строки (массив символов).
typedef struct string
{
char *text;
} *string;
int main()
{
int length = 50;
string s = (string) malloc(sizeof string);
s->text = (char *) malloc(len * sizeof char);
strcpy(s->text, patient.name->text);
}
Может кто-нибудь помочь мне понять это?
Спасибо.
Ответы
Ответ 1
О строках и распределении памяти:
Строка в C - это просто последовательность char
, поэтому вы можете использовать char *
или массив char
везде, где вы хотите использовать строковый тип данных:
typedef struct {
int number;
char *name;
char *address;
char *birthdate;
char gender;
} patient;
Затем вам нужно выделить память для самой структуры и для каждой из строк:
patient *createPatient(int number, char *name,
char *addr, char *bd, char sex) {
// Allocate memory for the pointers themselves and other elements
// in the struct.
patient *p = malloc(sizeof(struct patient));
p->number = number; // Scalars (int, char, etc) can simply be copied
// Must allocate memory for contents of pointers. Here, strdup()
// creates a new copy of name. Another option:
// p->name = malloc(strlen(name)+1);
// strcpy(p->name, name);
p->name = strdup(name);
p->address = strdup(addr);
p->birthdate = strdup(bd);
p->gender = sex;
return p;
}
Если вам понадобятся только несколько patient
, вы можете избежать управления памятью за счет выделения большего объема памяти, чем вам действительно нужно:
typedef struct {
int number;
char name[50]; // Declaring an array will allocate the specified
char address[200]; // amount of memory when the struct is created,
char birthdate[50]; // but pre-determines the max length and may
char gender; // allocate more than you need.
} patient;
В связанных списках:
В общем, цель связанного списка состоит в том, чтобы доказать быстрый доступ к упорядоченному набору элементов. Если ваш llist
содержит элемент с именем num
(который предположительно содержит номер пациента), вам нужна дополнительная структура данных, чтобы удерживать самого patient
, и вам нужно каждый раз искать номер пациента.
Вместо этого, если вы заявляете
typedef struct llist
{
patient *p;
struct llist *next;
} list;
то каждый элемент содержит прямой указатель на структуру patient
, и вы можете получить доступ к следующим данным:
patient *getPatient(list *patients, int num) {
list *l = patients;
while (l != NULL) {
if (l->p->num == num) {
return l->p;
}
l = l->next;
}
return NULL;
}
Ответ 2
Хотя Ричард - это то, что вам нужно, если вы хотите пойти с typedef, я бы предположил, что это, вероятно, не особенно хорошая идея в этом случае, поскольку вы теряете из виду, что это указатель, но ничего не набираете.
Если вы рассматривали это как подсчитанную строку или что-то с дополнительными функциями, это могло бы быть другим, но я бы рекомендовал, чтобы в этом случае вы просто познакомились с "стандартной" реализацией строки C, являющейся "char *"...
Ответ 3
Это не работает:
string s = (string)malloc(sizeof string);
string
относится к указателю, вам нужен размер самой структуры:
string s = malloc(sizeof (*string));
Обратите внимание на отсутствие литых (преобразование из void*
(тип возврата malloc
) неявно выполняется).
Кроме того, в main
, у вас есть глобально деликатный patient
, но это неинициализируется. Пытаться:
patient.number = 3;
patient.name = "John";
patient.address = "Baker street";
patient.birthdate = "4/15/2012";
patient.gender = 'M';
перед тем, как прочитать доступ к любому из его членов
Кроме того, strcpy
по своей сути является небезопасным, так как он не имеет проверки границ (будет скопирован до тех пор, пока не встретится первое '\0'
, написание выделенной ранее памяти, если источник слишком длинный). Вместо этого используйте strncpy
, где вы можете как минимум указать максимальное количество копируемых символов - прочитайте документацию, чтобы убедиться, что вы передаете правильное значение, легко сделать ошибку "один за другим".
Ответ 4
Вы можете просто использовать еще более простой typedef
:
typedef char *string;
Затем ваш malloc будет выглядеть как обычный malloc:
string s = malloc(maxStringLength);