Как работать со строковыми полями в 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);