構造体の引数
構造体で情報を渡す
構造体変数は、それ自体が1つの変数として扱われます。
したがって、構造体型の引数を使うことが出来、1度に複数の情報を渡すことができます。
構造体型の引数も、今までの引数とまったく同じ方法で指定できます。
ただし、typedefで宣言していない場合は、structをタグ名の前につける必要があります。
次の関数は、student型の構造体変数を引数として受け取る関数です。
受け取る側の関数での使い方も、通常の引数とまったく同じです。
次の関数は、student型の内容をすべて表示するものです。
配列の時は、引数にしても、渡されるのは先頭アドレスだけでしたが、
構造体型の引数は、受け取る側の関数にすべての値がコピーされます。
したがって、受け取る側の関数で引数の中身を変更しても、元の構造体変数には影響しません。
呼び出し側でも、通常の変数とまったく同じ方法で呼び出すことができます。
次のプログラムは、先ほどの関数を呼び出す例です。
このプログラムの実行結果は次の通りになります。
この関数は、student型の構造体変数の中身をすべて表示します。
したがって、構造体型の引数を使うことが出来、1度に複数の情報を渡すことができます。
構造体型の引数も、今までの引数とまったく同じ方法で指定できます。
ただし、typedefで宣言していない場合は、structをタグ名の前につける必要があります。
次の関数は、student型の構造体変数を引数として受け取る関数です。
student型の構造体変数を引数として受け取る関数
void student_print(student data)
受け取る側の関数での使い方も、通常の引数とまったく同じです。
次の関数は、student型の内容をすべて表示するものです。
student型の内容をすべて表示する関数
void student_print(student data)
{
printf("[学年]:%d\n", data.year);
printf("[クラス]:%d\n", data.clas);
printf("[出席番号]:%d\n", data.number);
printf("[名前]:%s\n", data.name);
printf("[身長]:%f\n", data.stature);
printf("[体重]:%f\n", data.weight);
return;
}
配列の時は、引数にしても、渡されるのは先頭アドレスだけでしたが、
構造体型の引数は、受け取る側の関数にすべての値がコピーされます。
したがって、受け取る側の関数で引数の中身を変更しても、元の構造体変数には影響しません。
呼び出し側でも、通常の変数とまったく同じ方法で呼び出すことができます。
次のプログラムは、先ほどの関数を呼び出す例です。
ソースコード
#include <stdio.h>
#include <string.h>
typedef struct
{
int year; /* 学年 */
int clas; /* クラス */
int number; /* 出席番号 */
char name[64]; /* 名前 */
double stature; /* 身長 */
double weight; /* 体重 */
} student;
void student_print(student data);
int main(void)
{
student data;
data.year = 3;
data.clas = 4;
data.number = 18;
strcpy(data.name, "MARIO");
data.stature = 168.2;
data.weight = 72.4;
student_print(data); /* 呼び出し */
return 0;
}
void student_print(student data)
{
printf("[学年]:%d\n", data.year);
printf("[クラス]:%d\n", data.clas);
printf("[出席番号]:%d\n", data.number);
printf("[名前]:%s\n", data.name);
printf("[身長]:%f\n", data.stature);
printf("[体重]:%f\n", data.weight);
return;
}
このプログラムの実行結果は次の通りになります。
実行結果
[学年]:3
[クラス]:4
[出席番号]:18
[名前]:MARIO
[身長]:168.200000
[体重]:72.400000
[クラス]:4
[出席番号]:18
[名前]:MARIO
[身長]:168.200000
[体重]:72.400000
この関数は、student型の構造体変数の中身をすべて表示します。
構造体の中の配列
構造体の中に配列が含まれている場合は、配列の中身もコピーされて渡されます。
したがって、中身を変更しても、呼び出し元の変数には影響しません。
配列をコピーして渡したい時(たとえば、リバーシのプログラムで盤面情報を渡したい等)には、
構造体にしてしまうのが一番簡単です。
したがって、中身を変更しても、呼び出し元の変数には影響しません。
配列をコピーして渡したい時(たとえば、リバーシのプログラムで盤面情報を渡したい等)には、
構造体にしてしまうのが一番簡単です。
構造体でもポインタ変数
構造体型のポインタ変数を作ることができます。宣言の方法などは同じです。
次のプログラムは、student型へのポインタ変数を使用する例です。
構造体の各要素は、宣言の時の順番通りに並んでおり、
&演算子で求められるアドレスは、構造体の始めの要素のアドレスです。
構造体のポインタ変数の場合も、*記号で通常変数モードに切り替えることができます。
ただし、.の方が優先されるので、かっこをつけて次のようにします。
ただ、(*)をつけるのは面倒なので、次の書き方で代用できるようになっています。
->は、引き算と比較記号を組み合わせた記号です。
例によって、引き算とも比較ともまったく関係はなく、記号を流用しているだけです
この書き方なら、より簡易的な書式で、各要素にアクセスできます。
次のプログラムは、->記号を使って各要素にアクセスする例です。
次のプログラムは、student型へのポインタ変数を使用する例です。
ソースコード
#include <stdio.h>
#include <string.h>
typedef struct
{
int year; /* 学年 */
int clas; /* クラス */
int number; /* 出席番号 */
char name[64]; /* 名前 */
double stature; /* 身長 */
double weight; /* 体重 */
} student;
int main(void)
{
student data;
student *pdata;
pdata = &data; /* 初期化 */
(*pdata).year = 10; /* 通常変数モードへの切り替え */
strcpy((*pdata).name, "MARIO"); /* 通常変数モードへの切り替え */
return 0;
}
構造体の各要素は、宣言の時の順番通りに並んでおり、
&演算子で求められるアドレスは、構造体の始めの要素のアドレスです。
構造体のポインタ変数の場合も、*記号で通常変数モードに切り替えることができます。
ただし、.の方が優先されるので、かっこをつけて次のようにします。
構造体のポインタ変数経由で要素にアクセス
(*構造体ポインタ変数名).要素名
ただ、(*)をつけるのは面倒なので、次の書き方で代用できるようになっています。
構造体のポインタ変数経由で要素にアクセス
構造体ポインタ変数名->要素名
->は、引き算と比較記号を組み合わせた記号です。
例によって、引き算とも比較ともまったく関係はなく、記号を流用しているだけです
この書き方なら、より簡易的な書式で、各要素にアクセスできます。
次のプログラムは、->記号を使って各要素にアクセスする例です。
ソースコード
int main(void)
{
student data;
student *pdata;
pdata = &data; /* 初期化 */
pdata->year = 10; /* ->記号によるアクセス */
strcpy(pdata->name, "MARIO"); /* ->記号によるアクセス */
return 0;
}
構造体でもポインタ引数
前項では、構造体でもポインタ変数にすることができると説明しましたが、
同様にして、構造体型へのポインタ型の引数を持つ関数も作ることができます。
次のプログラムは、先ほどの関数を、ポインタ変数を使うよう改めた例です。
まず、引数の型がポインタ型として宣言されていることがわかります。
関数を呼び出す時には、&演算子をつけて、アドレスを渡していることもわかります。
また、呼び出された関数内では、->記号で各要素にアクセスしています。
普通に渡すことができる構造体を、ポインタ変数として渡す理由の
1つ目は、普通のポインタ変数と同じく、関数内で値を変更できるようにするためです。
ここでは試していませんが、関数内で値を変えると呼び出し元の変数の中身も変わります。
2つ目は、関数呼び出しの高速化のためです。
構造体を渡す時、その中身はすべてコピーされます。
構造体の中に、大きな配列があれば、その中身までまるごとコピーされます。
これは、当然ながらそれなりに時間のかかる処理となります。
しかし、ポインタのアドレス値を渡すだけなら、非常に高速です。
しかし、現代のコンピュータはとても高速なので、値渡しであっても、それほど問題にはなりません。
慣れないうちは、値渡しのほうが扱いやすいため、値渡しで行うことをおすすめします。
同様にして、構造体型へのポインタ型の引数を持つ関数も作ることができます。
次のプログラムは、先ほどの関数を、ポインタ変数を使うよう改めた例です。
ソースコード
#include <stdio.h>
#include <string.h>
typedef struct
{
int year; /* 学年 */
int clas; /* クラス */
int number; /* 出席番号 */
char name[64]; /* 名前 */
double stature; /* 身長 */
double weight; /* 体重 */
} student;
void student_print(student *data);
int main(void)
{
student data;
data.year = 3;
data.clas = 4;
data.number = 18;
strcpy(data.name, "MARIO");
data.stature = 168.2;
data.weight = 72.4;
student_print(&data); /* アドレスで呼び出す */
return 0;
}
void student_print(student *data)
{
printf("[学年]:%d\n", data->year); /* ->記号でアクセス */
printf("[クラス]:%d\n", data->clas);
printf("[出席番号]:%d\n", data->number);
printf("[名前]:%s\n", data->name);
printf("[身長]:%f\n", data->stature);
printf("[体重]:%f\n", data->weight);
return;
}
まず、引数の型がポインタ型として宣言されていることがわかります。
関数を呼び出す時には、&演算子をつけて、アドレスを渡していることもわかります。
また、呼び出された関数内では、->記号で各要素にアクセスしています。
普通に渡すことができる構造体を、ポインタ変数として渡す理由の
1つ目は、普通のポインタ変数と同じく、関数内で値を変更できるようにするためです。
ここでは試していませんが、関数内で値を変えると呼び出し元の変数の中身も変わります。
2つ目は、関数呼び出しの高速化のためです。
構造体を渡す時、その中身はすべてコピーされます。
構造体の中に、大きな配列があれば、その中身までまるごとコピーされます。
これは、当然ながらそれなりに時間のかかる処理となります。
しかし、ポインタのアドレス値を渡すだけなら、非常に高速です。
しかし、現代のコンピュータはとても高速なので、値渡しであっても、それほど問題にはなりません。
慣れないうちは、値渡しのほうが扱いやすいため、値渡しで行うことをおすすめします。
本サイトについて
苦しんで覚えるC言語(苦C)はC言語入門サイトの決定版です。
C言語の基本機能を体系立てて解説しており、
市販書籍と同等以上の完成度です。




