この学習ノートは 2021 年 11 月に作成されました。当時、私が受講していた教材は C 言語で実装されていると主張していましたが、実際には C++ の構文がいくつか使用されていました。これは初心者にとって非常に使いにくいものでしたので、私はデータ構造に関する一連の学習ノートを作成しました。これらのノートはすべて純粋な C 言語で実装されています。Redis のソースコードを参考にした部分も多くあります。例えば、双方向リストやハッシュテーブルなどです。もし間違いを見つけた場合は、いつでも指摘していただければ修正します。このノートがコンピュータの初心者の友人たちにとって参考になれば幸いです。
ポインタについて#
ポインタは C 言語の中核であり、リンク構造を表すための重要な要素です。ポインタの基本的な概念を理解し、単方向リストなどのリンク構造を理解することはもはや難しい問題ではありません。
ポインタとポインタ変数の理解#
変数はデータを格納するためのものであり、ポインタはメモリアドレスです。ポインタ変数はメモリアドレスを格納するための変数です。
// 整数型の変数ageを宣言し、値を17に設定します
int age = 17;
// 整数型のポインタを宣言し、変数ageのアドレスを指すようにします。&記号は「アドレスを取得する記号」と考えることができます。
int *p = &age;
printf("ageの値:%d\n", age);
printf("*pの値:%d\n", *p);
printf("変数ageのアドレス:%p\n", &age);
printf("ポインタpが指すアドレス:%p\n", p);
printf("ポインタp自体のアドレス:%p\n", &p);
出力結果は次のようになります:
ageの値:17
*pの値:17
変数ageのアドレス:000000000062FE1C
ポインタpが指すアドレス:000000000062FE1C
ポインタp自体のアドレス:000000000062FE10
ポインタの図解#
メモリについて#
メモリアドレスについて疑問が生じるかもしれませんが、次のように大まかに理解することができます。
変数名 | メモリアドレス | 値 |
---|---|---|
age | 000000000062FE1C | 17 |
p | 000000000062FE10 | 000000000062FE1C |
整数型のポインタ変数 p は、整数型の変数 age のメモリアドレスを格納しています。
記号&
はアドレスを取得する記号ですので、&age = 000000000062FE1C です。ポインタ変数自体も変数ですので、p には自分自身のアドレスがあります。アドレスを取得する操作は & p = 000000000062FE10 です。そして、*p
はポインタ変数 p が格納している値に対応するメモリアドレスに格納されている値を取得します。
struct の宣言#
構造体(struct)は、C プログラミングでよく使用されるもので、オブジェクトのような属性だけでなく、メソッドのないものとして理解できます。構造体の宣言は、オブジェクトの構成レイアウトを記述します。
学生を表す struct を宣言してみましょう:
struct student {
char name[64];
int age;
int class;
}
ここでstudent
は構造体タグと呼ばれます。struct student
をint
のような変数の型のように考えることができます。その後、この構造体を使用することができます:
struct の初期化#
すべての属性を一度に初期化できます#
struct student stu = {"austin", 19, 3};
注意:
中括弧内の値の順序は、構造体の属性の順序と一致している必要があります。
宣言後に個別に初期化することもできます#
struct student stu;
strcpy(stu.name, "austin");
stu.age = 19;
stu.class = 3;
strcpy 関数について
strcpy 関数は C 標準ライブラリ <string.h> から提供されており、使用する際にはinclude
を忘れないでください。C 言語にはString
のような変数型はないため、通常は文字配列を使用して文字列を表現しますが、文字配列には直接文字列を代入することはできません。しかし、strcpy
関数を使用することでこの問題を解決することができます。
構造体の属性宣言と変数宣言を組み合わせることもできます#
struct student {
char name[64];
int age;
int class;
}stu;
/* その後、この構造体を初期化することができます
strcpy(stu.name, "austin");
stu.age = 19;
stu.class = 3; */
初期化を一緒に書くこともできます#
struct student {
char name[64];
int age;
int class;
}stu = {"austin", 19, 3};
複数の変数を一緒に初期化することもできます:
struct student {
char name[64];
int age;
int class;
}stu = {"austin", 19, 3},
stu2 = {"tim", 78, 100};
構造体のタグを省略することもできます#
struct student
の変数stu
だけが必要な場合、構造体のタグstudent
を省略することができます:
struct {
char name[64];
int age;
int class;
}stu;
これにより、struct student stu
のように他の変数を宣言することはできなくなります。
struct の使用#
構造体変数を定義する場合は、. を使用してメンバにアクセスします。
構造体ポインタを定義する場合は、-> を使用してメンバにアクセスします。
struct student {
char name[64];
int age;
int class;
}stu;
// 構造体変数の初期化
strcpy(stu.name, "austin");
stu.age = 19;
stu.class = 3;
struct student *stu_ptr = &stu;
// .を使用して構造体変数のメンバにアクセスする
printf("age: %d\n", stu.age);
// ->を使用してアクセスする
printf("age: %d\n", stu_ptr->age);
typedef の使用#
たとえば、次のような構造体があるとします:
struct student {
char name[64];
int age;
int class;
}
上記のように、この構造体を使用する場合、struct student stu
のように変数を宣言します。
typedef
キーワードを使用してstruct student
に別名を指定できます:
typedef struct student s;
上記のコードでは、struct student
をs
という別名に指定しています。したがって、s stu;
の文はstruct student stu;
と等価です。より簡潔で便利です。
構造体を定義する際にtypedef
キーワードを使用することもできます。上記のコードを次のように統合できます:
typedef struct student {
char name[64];
int age;
int class;
}s;
まとめ#
struct
の使用方法はさまざまですが、理解するのは難しくありません。struct
の使用方法を熟練させることをお勧めします。これはデータ構造の基本的な構文です。