複数の型をまとめる

構造体の引数

MMGames

構造体



構造体で情報を渡す


構造体変数は、それ自体が1つの変数として扱われます。
従って、構造体型の引数を使うことが出来、1度に複数の情報を渡すことが出来ます。

構造体型の引数も、今までの引数と全く同じ方法で指定出来ます。
ただし、typedefで宣言していない場合は、structをタグ名の前につける必要があります。
次の関数は、student型の構造体変数を引数として受け取る関数です。

void student_print(student data)
受け取る側の関数での使い方も、通常の引数と全く同じです。
次の関数は、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
この関数は、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;
}
*記号をつけてかっこで囲むよりも、この書き方が簡単です。


構造体でもポインタ引数


前項では、構造体でもポインタ変数にすることが出来ると説明しましたが、
同様にして、構造体型へのポインタ型の引数を持つ関数も作ることが出来ます。
次のプログラムは、先ほどの関数を、ポインタ変数を使うよう改めた例です。

#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つ目は、関数呼び出しの高速化のためです。
構造体を渡す時、その中身は全てコピーされます。
構造体の中に、大きな配列があれば、その中身までまるごとコピーされます。
これは、当然ながらそれなりに時間のかかる処理となります。
しかし、ポインタのアドレス値を渡すだけなら、ほとんど時間はかかりません。

一般には、構造体はポインタ変数を使って受け渡しすることが多いようですが、
中の値を書き換えてしまうなどのトラブルにも見舞われやすいので、
慣れない内は、普通に受け渡ししていた方が簡単だと思います。

サイト目次


第0部:プログラム概要編

  1. プログラムとは何か?

2章:プログラムの書き方

  1. 書き方のルール
  2. 書き方の慣習
  3. 練習問題2

3章:画面への表示

  1. 文字列の表示
  2. 改行文字
  3. 練習問題3

6章:キーボードからの入力

  1. 入力用の関数
  2. 入力の恐怖
  3. 練習問題6

9章:回数が決まっている繰り返し

  1. 繰り返しを行う文
  2. ループ動作の仕組み
  3. 練習問題9

10章:回数がわからない繰り返し

  1. 回数不明ループ
  2. 入力チェック
  3. 練習問題10

13章:複数の変数を一括して扱う

  1. 複数の変数をまとめて扱う
  2. 配列の使い方
  3. 練習問題13

20章:複数のソースファイル

  1. 最小限の分割
  2. 分割の定石
  3. 練習問題20