【C言語/C++の実装構造とポインタ詳細チュートリアル】

構造体とポインタ

構造

C 言語の構造体は、さまざまな種類のデータを組み合わせて新しいデータ型を形成できるカスタム データ型です。構造体には、整数、文字、浮動小数点数、配列などのさまざまなタイプのデータを含めることができ、複雑なデータ構造を記述するために使用できます。C言語における構造体について、構造体の定義、構造体変数の宣言と初期化、構造体のメンバへのアクセスなどを詳しく紹介します。

1. 構造の定義

構造体の定義ではキーワードstructを使用し、その構文は次のとおりです。

struct 構造体名 {
データ型メンバ名 1;
データ型メンバ名 2;
データ型メンバ名 3;
...
};

このうち、構造体名はカスタム名、メンバー名は構造体の各要素に付ける名前、データ型は C 言語のデータ型またはその他の構造体型にすることができます。

たとえば、名前、年齢、性別、学生番号、成績などの学生の情報を表す構造を定義できます。コードは次のとおりです。

struct Student {
    
    
    char name[20];
    int age;
    char sex;
    char id[10];
    float score;
};

上記のコードでは、Student という構造体を定義しています。この構造体には、名前、年齢、性別、学生番号、学年の 5 つのメンバーが含まれており、データ型は char、int、char、char、float です。

2. 構造体変数の宣言と初期化

構造体が定義されたら、構造体変数を宣言して初期化できます。構造体変数を宣言して初期化するには、次の 2 つの方法があります。

1. 最初に宣言してから初期化する

struct Student stu;
stu.age = 18;
strcpy(stu.name, "Tom");
stu.sex = 'M';
strcpy(stu.id, "2018001");
stu.score = 95.0;

上記のコードでは、最初に Student 型の stu という名前の構造体変数を宣言し、次にそのメンバーを初期化します。

2. 同時宣言と初期化

struct Student stu = {
    
    "Tom", 18, 'M', "2018001", 95.0};

上記のコードでは、宣言中に stu 構造体変数を初期化していますが、初期化の順序はメンバー定義の順序と一致しています。

3. 構造体メンバーへのアクセス

構造体メンバーへのアクセスには、次のように「 . 」演算子を使用します。

printf("姓名:%s\n", stu.name);
printf("年龄:%d\n", stu.age);
printf("性别:%c\n", stu.sex);
printf("学号:%s\n", stu.id);
printf("成绩:%f\n", stu.score);

上記のコードでは、「.」演算子を使用して stu 構造体変数の各メンバーにアクセスし、その値を出力します。

4番目、関数パラメータとしての構造体

構造体は関数のパラメータとして使用できます。次に例を示します。

void printStudent(struct Student s) {
    
    
    printf("姓名:%s\n", s.name);
    printf("年龄:%d\n", s.age);
    printf("性别:%c\n", s.sex);
    printf("学号:%s\n", s.id);
    printf("成绩:%f\n", s.score);
}

上記のコードでは、Student 型の構造体変数 s をパラメータとする printStudent という関数を定義し、s 変数のメンバーを出力します。

5、完全なコード

以下は、構造体の使用の完全な例です。この例では、Student という名前の構造体を定義し、stu という名前の構造体変数を宣言し、それを初期化し、最後に stu 変数のメンバーを出力します。

#include <stdio.h>
#include <string.h>

struct Student {
    
    
    char name[20];
    int age;
    char sex;
    char id[10];
    float score;
};

void printStudent(struct Student s) {
    
    
    printf("姓名:%s\n", s.name);
    printf("年龄:%d\n", s.age);
    printf("性别:%c\n", s.sex);
    printf("学号:%s\n", s.id);
    printf("成绩:%f\n", s.score);
}

int main() {
    
    
    struct Student stu = {
    
    "Tom", 18, 'M', "2018001", 95.0};
    printStudent(stu);
    return 0;
}

操作の結果は次のようになります。

姓名:Tom
年龄:18
性别:M
学号:2018001
成绩:95.000000

6. まとめ

この記事では、構造体の定義、構造体変数の宣言と初期化、構造体のメンバーへのアクセス、関数の引数としての構造体など、C言語の構造体について紹介します。構造は非常に重要なデータ型であり、複雑なデータ構造を記述するために使用でき、プログラムの作成やメンテナンスに便利です。

ポインタ

ポインタは C 言語において非常に重要な概念ですが、初心者にとっては理解するのが最も難しい概念の 1 つでもあります。ポインタの本質は、データが保存されている場所を指すアドレスです。ポインタを介して、この場所に保存されているデータにアクセスして操作できます。以下では、C 言語のポインタの関連概念と使用法を、詳細なコードとコードの説明とともに詳しく説明します。

1. ポインタの定義

ポインタの定義形式は次のとおりです: *データ型ポインタ変数名; ここで、データ型はポインタが指すデータ型を示し、ポインタ変数名はメモリ内のポインタ変数の位置を示すために使用される識別子です。例えば:

int *p; //定义一个指向整型数据的指针变量

ポインタ変数を定義する場合は、ポインタが指すデータ型を指定する必要があります。これは、異なるデータ型が占有する記憶領域のサイズが異なるためであり、ポインター操作を正しく実行するには、ポインターが指すデータ型のサイズを知る必要があるためです。

次に、ポインタの初期化

ポインタ変数は、定義時に特定のアドレスを自動的に指すわけではないため、ポインタ変数が正当なメモリ アドレスを指すように初期化する必要があります。ポインター変数は次の方法で初期化できます。

① 直接代入:ポインタ変数を既知のアドレスに代入します。

int a = 10;
int *p = &a; //将指针p指向变量a的地址

② malloc 関数を使用して動的にメモリを割り当てます。

int *p = (int *)malloc(sizeof(int)); //动态分配一个整型数据的内存空间,并将指针p指向这个空间的地址

③関数の戻り値による初期化:

int *get_array(int size) {
    
    
    int *p = (int *)malloc(size * sizeof(int));
    return p;
}

int *arr = get_array(10); //将指针arr指向动态分配的数组的首地址

3、ポインタ操作

ポインタ変数は加算および減算が可能で、ポイントされたアドレスは演算結果に応じてオフセットされます。例えば:

int a[5] = {
    
    1, 2, 3, 4, 5};
int *p = a; //将指针p指向数组a的首地址

for (int i = 0; i < 5; i++) {
    
    
    printf("%d ", *p); //输出指针p所指向的数据
    p++; //指针p指向下一个数据
}

上記のコードでは、ポインタ p はまず配列 a の最初のアドレスを指し、次にポインタ演算を使用して配列内の各要素に順番にアクセスし、その値を出力します。

ポインタ変数は、それらが指すアドレスが同じかどうかを比較する比較演算も実行できます。例えば:

int a = 10, b = 20;
int *p1 = &a, *p2 = &b;

if (p1 > p2) {
    
    
    printf("p1指向的地址大于p2\n");
} else {
    
    
    printf("p1指向的地址小于等于p2\n");
}

上記コードでは、ポインタ変数 p1 と p2 を比較することで、それらが指すアドレスの大きさを判定し、その結果を出力しています。

4番目、ポインタの適用

ポインタは C 言語で広く使用されており、次の側面で使用できます。

① 動的メモリ割り当て: ポインタと malloc 関数を通じてメモリ空間を動的に割り当てることができ、静的割り当て時のメモリの無駄の問題を回避します。

② 関数パラメータの受け渡し:関数パラメータをポインタを介して受け渡し、関数内の計算結果を呼び出し元に返すことができます。

void swap(int *x, int *y) {
    
    
    int temp = *x;
    *x = *y;
    *y = temp;
}

int a = 10, b = 20;
swap(&a, &b); //将变量a和b的值交换

上記のコードでは、ポインタを介して変数aとbの値を交換することで関数の機能を実現しています。

③ 配列アクセス: 配列名は基本的に配列の先頭アドレスへのポインタであり、配列内の各要素はポインタを通じてアクセスできます。

int a[5] = {
    
    1, 2, 3, 4, 5};
int *p = a; //将指针p指向数组a的首地址

for (int i = 0; i < 5; i++) {
    
    
    printf("%d ", *(p + i)); //输出数组中的每个元素
}

上記のコードでは、ポインタ p を通じて配列 a の各要素にアクセスし、その値を出力しています。

5. ポインタに関する注意事項

ポインタを使用する場合は、次の点に注意する必要があります。

① ポインタ変数は使用する前に初期化する必要があります。

② ポインタ変数は未割り当てのメモリ空間にアクセスできません。そうしないとプログラムがクラッシュします。

③ ポインタ変数は正しいデータ型を指している必要があります。そうでない場合、ポインタ演算エラーが発生します。

④ ポインタ変数を使用する場合は、境界外アクセスを避けるためにポインタ演算の境界問題に注意する必要があります。

6. コード例

以下は、ポインターの定義、初期化、操作、および適用を示す完全なサンプル コードです。

#include <stdio.h>
#include <stdlib.h>

void swap(int *x, int *y) {
    
    
    int temp = *x;
    *x = *y;
    *y = temp;
}

int *get_array(int size) {
    
    
    int *p = (int *)malloc(size * sizeof(int));
    return p;
}

int main() {
    
    
    int a = 10, b = 20;
    int *p1 = &a, *p2 = &b;
if (p1 > p2) {
    
    
    printf("p1指向的地址大于p2\n");
} else {
    
    
    printf("p1指向的地址小于等于p2\n");
}

int arr[5] = {
    
    1, 2, 3, 4, 5};
int *p = arr;

for (int i = 0; i < 5; i++) {
    
    
    printf("%d ", *(p + i));
}
printf("\n");

int *arr2 = get_array(10);
for (int i = 0; i < 10; i++) {
    
    
    *(arr2 + i) = i;
    printf("%d ", *(arr2 + i));
}
printf("\n");

swap(&a, &b);
printf("a=%d, b=%d\n", a, b);

free(arr2);

return 0;
}

上記のコードでは、2 つのポインタ変数 p1 と p2 が定義されており、それらが指すアドレスの大小を比較することにより、対応する結果が出力されます。次に、配列 arr が定義され、配列内の各要素はポインタ変数 p を介してアクセスされ、その値が出力されます。次に、関数 get_array を通じて配列が動的に割り当てられ、配列内の各要素はポインタ変数 arr2 を通じてアクセスされ、その値が出力されます。最後に変数aとbの値を関数swapで交換し、その値を出力します。動的に割り当てられた配列を使用した後は、free 関数を使用してメモリ空間を解放する必要があることに注意してください。

7. まとめ

この記事では、ポインタの定義、初期化、操作、応用など、C 言語におけるポインタの関連概念と使用法について詳しく説明します。ポインタは C 言語で広く使用されており、動的なメモリ割り当て、関数パラメータの受け渡し、配列アクセスなどに使用できます。ポインターを使用する場合は、ポインター変数の初期化、指すデータ型、境界の問題などに注意する必要があります。この記事の学習を通じて、読者はポインタの理解と応用能力についてより深く理解できると思います。

おすすめ

転載: blog.csdn.net/qq_43884946/article/details/131276067