構造体は配列でない変数と同じように代入を行ったり, 関数の引数として用いることができる.
#include <stdio.h>
#include <stdlib.h>
double func(double a)
{
double ret;
ret = a + 1.0;
return ret;
}
int main(void)
{
double a = 2.0;
double b, c;
b = a;
printf("b = %f\n", b);
c = func(a);
printf("c = %f\n", c);
return EXIT_SUCCESS;
}
次のプログラムでは struct COMPLEX が 上のプログラムの doubleと同じように扱われていることに注意.
#include <stdio.h>
#include <stdlib.h>
struct COMPLEX {
double x;
double y;
};
struct COMPLEX func(struct COMPLEX a)
{
struct COMPLEX ret;
ret.x = a.x + 1.0;
ret.y = a.y + 1.0;
return ret;
}
int main(void)
{
struct COMPLEX a = {10.0, 20.0};
struct COMPLEX b, c;
b = a;
printf("b = (%f, %f)\n", b.x, b.y);
c = func(a);
printf("c = (%f, %f)\n", c.x, c.y);
return EXIT_SUCCESS;
}
[課題1] 複素数の和, 積を求める関数を追加し動作を確認できるようmainを変更せよ。
関数の引数をアドレスにする場合も, double 型と struct COMPLEX型が等価である.
#include <stdio.h>
#include <stdlib.h>
void func(double *a)
{
*a += 1.0;
}
int main(void)
{
double a = 2.0;
printf("a = %f\n", a);
func(&a);
printf("a = %f\n", a);
return EXIT_SUCCESS;
}
#include <stdio.h>
#include <stdlib.h>
void swap(double *a, double *b)
{
double tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
int main(void)
{
double x = 2.0;
double y = 4.0;
printf("(x, y) = (%f, %f)\n", x, y);
swap(&x, &y);
printf("(x, y) = (%f, %f)\n", x, y);
return EXIT_SUCCESS;
}
#include <stdio.h>
#include <stdlib.h>
struct COMPLEX {
double x;
double y;
};
// (*a).x の部分は a->x と表記できる.
void func(struct COMPLEX *a)
{
(*a).x += 1.0;
(*a).y += 2.0;
}
int main(void)
{
struct COMPLEX a = {10.0, 20.0};
printf("a = (%f, %f)\n", a.x, a.y);
func(&a);
printf("a = (%f, %f)\n", a.x, a.y);
return EXIT_SUCCESS;
}
[課題2] 上のプログラムを参考にして, 二つの複素数のを入れ替えるプログラムを作成せよ.
typedefにより定義しなおすと, double型や int型などの予め用意された型の変数と同様に, 自分で定義した構造体を扱うことができる.
#include <stdio.h>
#include <stdlib.h>
struct COMPLEX {
double x;
double y;
};
typedef struct COMPLEX complex;
void func(complex *a)
{
(*a).x += 1.0;
(*a).y += 2.0;
}
int main(void)
{
complex a = {10.0, 20.0};
printf("a = (%f, %f)\n", a.x, a.y);
func(&a);
printf("a = (%f, %f)\n", a.x, a.y);
return EXIT_SUCCESS;
}
構造体の配列はdouble型の配列と同じように代入できる.
#include <stdio.h>
#include <stdlib.h>
#define N 5
int main(void)
{
int i;
double a[N] = {1.0, 2.0, 3.0, 4.0, 5.0};
double b[N];
// 直接 b = a のように代入はできないので各要素を代入する.
for(i=0; i<N; i++)
b[i] = a[i];
for(i=0; i<N; i++)
printf("%f ", b[i]);
printf("\n");
return EXIT_SUCCESS;
}
#include <stdio.h>
#include <stdlib.h>
struct COMPLEX {
double x;
double y;
};
typedef struct COMPLEX complex;
#define N 5
int main(void)
{
int i;
complex a[N] = {{1.1, 1.2}, {2.1, 2.2}, {3.1, 3.2}, {4.1, 4.2}, {5.1, 5.2}};
complex b[N];
// 直接 b = a のように代入はできないので各要素を代入する.
for(i=0; i<N; i++)
b[i] = a[i];
for(i=0; i<N; i++)
printf("(%f, %f) ", b[i].x, b[i].y);
printf("\n");
return EXIT_SUCCESS;
}
配列を受け取る関数.
#include <stdio.h>
#include <stdlib.h>
#define N 5
// アドレスを受け取る
void func(double *x)
{
int i;
for(i=0; i<N; i++)
x[i] += 0.3;
}
void double_print(double *x)
{
int i;
for(i=0; i<N; i++)
printf("%f ", x[i]);
printf("\n");
}
int main(void)
{
double a[N] = {1.0, 2.0, 3.0, 4.0, 5.0};
// 配列名a は &a[0] すなわち aの先頭アドレスを表すことになっている.
double_print(a);
func(a); // aの先頭アドレスが渡される。
double_print(a);
return EXIT_SUCCESS;
}
#include <stdio.h>
#include <stdlib.h>
struct COMPLEX {
double x;
double y;
};
typedef struct COMPLEX complex;
#define N 5
// アドレスを受け取る
void func(complex *p)
{
int i;
for(i=0; i<N; i++){
p[i].x += 0.2;
p[i].y += 0.4;
}
}
int main(void)
{
int i;
complex a[N] = {{1.1, 1.2}, {2.1, 2.2}, {3.1, 3.2}, {4.1, 4.2}, {5.1, 5.2}};
// 配列名a は &a[0] すなわち aの先頭アドレスを表すことになっている.
// a の値を表示 (1)
for(i=0; i<N; i++)
printf("(%f, %f) ", a[i].x, a[i].y);
printf("\n");
func(a); // aの先頭アドレスが渡される。
// a の値を表示 (2)
for(i=0; i<N; i++)
printf("(%f, %f) ", a[i].x, a[i].y);
printf("\n");
return EXIT_SUCCESS;
}
[課題3] 上のプログラムの 「a の値を表示」している部分2ヶ所を関数化せよ.
[課題4] 以下のプログラムを参考にして, 大きさが最大のベクトルを返す関数とその動作が確認できる main 関数を作成せよ.
ベクトルの長さを求めるプログラム:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
struct VECTOR {
char label[50];
double x;
double y;
double z;
};
typedef struct VECTOR vector;
#define N 3
double func(vector p)
{
double r;
r = sqrt( p.x * p.x + p.y * p.y + p.z * p.z );
return r;
}
int main(void)
{
int i;
vector a = {"A", 10.0, 20.0, 30.0};
vector b[N] = {
{"B1", 1.0, 2.0, 3.0},
{"B2", 1.1, 2.1, 3.1},
{"B3", 1.2, 2.2, 3.2},
};
printf("%sの長さ: %f\n", a.label, func(a));
for(i=0; i<N; i++)
printf("%sの長さ: %f\n", b[i].label, func(b[i]));
return EXIT_SUCCESS;
}
ベクトルの和 (合成ベクトル) を求めるプログラム:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
struct VECTOR {
char label[50];
double x;
double y;
double z;
};
typedef struct VECTOR vector;
vector add(vector p, vector q)
{
vector r;
// sprintf は書式に従って第1引数の文字列に代入する関数.
sprintf(r.label, "%s + %s", p.label, q.label);
r.x = p.x + p.x;
r.y = p.y + p.y;
r.z = p.z + p.z;
return r;
}
void vector_print(vector p)
{
printf("%s = (%f, %f, %f)\n", p.label, p.x, p.y, p.z);
}
int main(void)
{
vector a = {"A", 10.0, 20.0, 30.0};
vector b = {"B", 1.0, 2.0, 3.0};
vector c;
vector_print(a);
vector_print(b);
c = add(a, b);
vector_print(c);
return EXIT_SUCCESS;
}
[課題5] 2点間の距離を求めるプログラムを作成せよ.
[課題6] 2つのベクトルがなす角を求めるプログラムを作成せよ.
[課題7] 次に示すように構造体のメンバーとして配列を有する場合, 代入はどのように行われるか. また関数の引数としての渡すとき, どのように渡されるかを, double 型の変数と比較して答えよ。
struct DATA {
double x[100];
double y[100];
int n; // データ点の数
};
[課題8] 次に示すように構造体のメンバーとしてポインタ変数を有する場合について 課題8と同様の視点から double 型と比較せよ.
struct DATA {
double *x;
double *y;
int n; // データ点の数
};
struct DATA を用いた例:
#include <stdio.h>
#include <stdlib.h>
struct DATA {
double *x;
double *y;
int n;
};
typedef struct DATA data;
#define N 100
void data_print(data *d)
{
int i;
for(i=0; i < d->n; i++)
printf("(%f, %f)\n", d->x[i], d->y[i]);
}
int main(void)
{
int i;
double x[N], y[N];
data d;
// 初期化
d.x = x; // 領域の確保された配列を指すようにすること.
d.y = y;
d.n = N;
// y = x*x であるデータを代入
for(i=0; i<N; i++){
d.x[i] = (double)i;
d.y[i] = d.x[i] * d.x[i] ;
}
data_print(&d);
return EXIT_SUCCESS;
}
#include <stdio.h>
#include <stdlib.h>
struct DATA {
double *x;
double *y;
int n;
};
typedef struct DATA data;
#define N 100
void data_init(data *d, double x, double y, int n)
{
d->x = x;
d->y = y;
d->n = n;
}
void data_print(data *d)
{
int i;
for(i=0; i < d->n; i++)
printf("(%f, %f)\n", d->x[i], d->y[i]);
}
void data_set(data *d)
{
int i;
for(i=0; i < d->n; i++){
d->x[i] = (double)i;
d->y[i] = d->x[i] * d->x[i] ;
}
}
int main(void)
{
double x[N], y[N]; // 領域の確保が必要.
data d;
data_init(&d, x, y, N); // 初期化
data_set(&d); // y = x*x であるデータを代入
data_print(&d); // データの値を表示
return EXIT_SUCCESS;
}
[課題9] 上記2種類の構造体について, const で修飾された引数として関数に渡したとき, const が及ぶ範囲を答えよ.
(gcc の場合, const で修飾された変数に代入を行おうとするとコンパイラーがメッ セージを出力するので, それを基準とするとよい.)