web-dev-qa-db-ja.com

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;
_

次に、文字列型(charの配列)の新しいデータを作成する必要がある場合、それらのそれぞれを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);
}
_

誰かが私がこれを理解するのを助けることができますか?
ありがとうございました。

15
fleuracia

文字列とメモリの割り当て:

Cの文字列はcharsのシーケンスであるため、文字列データ型を使用する場合はどこでも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;
}

数個のpatientsのみが必要な場合は、実際に必要な量よりも多くのメモリを割り当てることを犠牲にして、メモリ管理を回避できます。

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;

リンクリスト:

一般に、リンクリストの目的は、要素の順序付けられたコレクションへの迅速なアクセスを証明することです。 llistnum(おそらく患者番号を含む)と呼ばれる要素を含む場合、実際のpatientsを保持するための追加のデータ構造が必要です。毎回患者番号を調べる。

代わりに、宣言する場合

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;
}
37
Adam Liss

Typedefを使用したい場合は、Richardを使用することをお勧めしますが、このインスタンスでは、特に何も得られずにポインターであることに気付かないため、特に良いアイデアではないことをお勧めします。

カウントされた文字列、または追加機能を備えたものを扱う場合は異なる可能性がありますが、この例では、「標準」C文字列の実装が「char *」であることに慣れることを本当にお勧めします。 ..

1
Gwyn Evans

これは動作しません:

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を使用します。少なくとも、コピーする最大文字数を指定できます。ドキュメントを読んで正しい値を渡すようにしてください。オフバイワンエラーが発生しやすくなります。

0
Attila

さらに単純なtypedefを使用することもできます。

typedef char *string;

次に、mallocは通常のmallocのようになります。

string s = malloc(maxStringLength);
0