• 検索結果がありません。

1 ( )

N/A
N/A
Protected

Academic year: 2021

シェア "1 ( )"

Copied!
25
0
0

読み込み中.... (全文を見る)

全文

(1)

プログラミング演習

I

レポート其の漆

所 属

:

琉球大学 工学部 情報工学科

学籍番号

:155727B

氏 名

:

多和田 真悟

提 出 日

:2015

7

30

(2)

目 次

1 演習問題 (ポインタとアドレス) 2 2 構造体 18 2.1 構造体とは . . . . 18 2.1.1 構造体の宣言 . . . . 18 2.1.2 構造体の初期化 . . . . 19 2.1.3 構造体のデータ参照 . . . . 20 2.2 構造体とポインタ . . . . 21 2.2.1 ポインタを用いた構造体の宣言 . . . . 21 2.2.2 ポインタ構造体のデータ参照 . . . . 22 2.3 関数と構造体 . . . . 24 3 あとがき 24

(3)

1

演習問題

(

ポインタとアドレス

)

ソースコード 1 #include <stdio.h> 2 3 int main(){ 4 {//Q1 5 puts("---"); 6 puts("Q1.変数 vのアドレスを求める式を示せ。"); 7 8 int v; 9

10 printf("A1.&v = %08x\n",&v);

11 puts("---"); 12 } 13 14 {//Q2 15 puts("---"); 16 puts("Q2.1次元配列 mの0番目から始まる5番目の要素のアドレスを求める式を、2つ示せ。"); 17 18 int m[5]; 19

20 printf("A2.&m[5] = %08x\n",&m[5]); 21 printf("A2.m+5 = %08x\n",m+5); 22 puts("---"); 23 } 24 25 {//Q3 26 puts("---"); 27 puts("Q3.1次元配列 mの先頭アドレスを求める式を、2つ示せ。"); 28 29 int m[0]; 30

31 printf("A3.&m[0] = %08x\n",&m[0]); 32 printf("A3.m[0] = %08x\n",m); 33 printf("A3.m = %08x\n",m); 34 puts("---"); 35 } 36 37 {//Q4 38 puts("---"); 39 puts("Q4.2次元配列 dの先頭アドレスを求める式を、3つ示せ。"); 40

(4)

41 int d[0][0]; 42

43 printf("A4.&d[0][0] = %08x\n",&d[0][0]); 44 printf("A4.&d[0] = %08x\n",&d[0]); 45 printf("A4.d[0] = %08x\n",d[0]); 46 printf("A4.*d = %08x\n",*d); 47 printf("A4.d = %08x\n",d); 48 puts("---"); 49 } 50 51 {//Q5 52 puts("---"); 53 puts("Q5.次の文を実行した後の変数aの値を示せ。"); 54 55 int a=2, b=3, c=5, *p, *q; 56 p = &b; 57 q = &c; 58 a = *p + *q;

59 puts("int a=2, b=3, c=5, *p, *q;"); 60 puts("p = &b;"); 61 puts("q = &c;"); 62 puts("a = *p + *q;\n"); 63 64 printf("A5.a = %d\n",a); 65 puts("---"); 66 } 67 68 {//Q6 69 puts("---"); 70 puts("Q6.次の文を実行した後の変数aの値を示せ。"); 71 72 int a=2, *p; 73 p = &a; 74 *p = 5;

75 puts("int a=2, *p;"); 76 puts("p = &a;"); 77 puts("*p = 5;\n"); 78 79 printf("A6.a = %d\n",a); 80 puts("---"); 81 } 82 83 {//Q7

(5)

84 puts("---"); 85 puts("Q7.次の文を実行した後の* p、* q、** qの値を示せ。"); 86 puts("但し、*(100)=200 -> アドレス100の値=200"); 87 puts("*(200)=300 -> アドレス200の値=300 とする。\n"); 88 89 int *p,**q,*r; 90 int a = 200; 91 int b = 300; 92 p = &a; 93 q = &r; 94 r = &b; 95 puts("int *p, **q,*r;"); 96 puts("int a=200;"); 97 puts("int b=300;");

98 puts("p = &a ,q = &r ,r = &b;");

99 puts("(& aをアドレス100,&bをアドレス200と考える)\n"); 100 printf("&a = %08x\n",&a);

101 printf("&b = %08x\n",&b); 102 printf("*p = %d\n",*p); 103 printf("*q = %08x\n",*q); 104 printf("**q = %d\n",**q); 105 106 printf("A7.*p=200,*q=%08x,**q=300\n",*q); 107 puts("---"); 108 } 109 110 {//Q8 111 puts("---"); 112 puts("Q8.1次元配列mにおいて、m [k] と *(m+k) はどのような値か述べよ 。"); 113 114 int m[5]={0,1,2,3,4}; 115 int n; 116 for(n=0;n<5;n++){ 117 printf("m[%d] = %d\n",n,m[n]); 118 printf("*(m+%d) = %d\n",n,*(m+n)); 119 } 120 121 puts("A8.m[k]は配列mのk番目の値を示しており,m +kは配列mの先頭(0番目)から kだけ増加し,\ n k番目のアドレスを示すため,*(m+k)ではm+ kの指す値を示している。"); 122 puts("---"); 123 } 124 125 {//Q9

(6)

126 puts("---"); 127 puts("Q9.整数型ポインタ変数pにおいて、p +2 は pの値を何バイト増加させた値か述べよ。\n 但し 、整数型データは4バイトとする 。"); 128 129 int *p; 130 printf("p = %08x\n",p); 131 printf("p+2 = %08x\n",p+2); 132 133 puts("A9.8バイト"); 134 puts("---"); 135 } 136 137 {//Q10 138 puts("---"); 139 puts("Q10.次の文章は正しいか述べよ 。"); 140 puts("a.1次元配列mは、* mのようにポインタ変数と同じ書式で使用しても良い。 "); 141 puts("b.ポインタ変数 p は 、p[0]のように配列名と同じ書式で使用しても良い。\n"); 142 143 puts("A10(a).正しいと言える 。"); 144 int m[2]={0,1}; 145 printf("m[0] => %d,*m => %d\n",m[0],*m); 146 printf("m[1] => %d,*(m+1) => %d\n\n",m[1],*(m+1)); 147 148 puts("A10(b).正しいと言える 。"); 149 int *n; 150 n = m; 151 printf("n[0] => %d,*n => %d\n",n[0],*n); 152 printf("n[1] => %d,*(n+1) => %d\n\n",n[1],*(n+1)); 153 puts("---"); 154 } 155 156 {//Q11 157 puts("---"); 158 puts("Q11.次の定義による,*m,*(m+3),*m+3,*m+*(m+3)の値を示せ 。"); 159 puts("static int m[5] = {10,20,40,50,30}\n");

160 161 static int m[5] = {10,20,40,50,30}; 162 printf("*m = %d\n",*m); 163 printf("*(m+3) = %d\n",*(m+3)); 164 printf("*m+3 = %d\n",*m+3); 165 printf("*m+*(m+3) = %d\n\n",*m+*(m+3)); 166 167 puts("A11.*m=10,*(m+3)=50,*m+3=13,*m+*(m+3)=60");

(7)

168 puts("---"); 169 } 170 171 {//Q12 172 puts("---"); 173 puts("Q12.次の定義による,*d[2],*(d[2]+2),*d[2]+2,**d,*(*d+3),\n **d+6,*(d[1]+2),**( d+2) の値を示せ 。");

174 puts("static int d[][3] = {{1,2,3},{5,6,7},{4,6,8},{9,7,5}};\n"); 175 176 static int d[][3] = {{1,2,3},{5,6,7},{4,6,8},{9,7,5}}; 177 printf("*d[2] = %d\n",*d[2]); 178 printf("*(d[2]+2) = %d\n",*(d[2]+2)); 179 printf("*d[2]+2 = %d\n",*d[2]+2); 180 printf("**d = %d\n",**d); 181 printf("*(*d+3) = %d\n",*(*d+3)); 182 printf("**d+6 = %d\n",**d+6); 183 printf("*(d[1]+2) = %d\n",*(d[1]+2)); 184 printf("**(d+2) = %d\n\n",**(d+2)); 185 186 puts("A12.*d[2]=4,*(d[2]+2)=8,*d[2]+2=6,**d=1,*(*d+3)=5,**d+6=7,*(d[1]+2)=7,**(d+2)=4" ); 187 puts("---"); 188 } 189 190 {//Q13 191 puts("---"); 192 puts("Q13.次の文を実行した後のポインタ変数 pの文字列を示せ。"); 193 puts("char *str = \"abcdefg\", *p");

194 puts("p = str + 3;"); 195 196 char *str = "abcdefg",*p; 197 p = str + 3; 198 printf("p = %s\n",p); 199

200 printf("A13.p = defg\n");

201 puts("---"); 202 } 203 204 {//Q14 205 puts("---"); 206 puts("Q14.次の文を実行した後のp,*p,*(p+2)の値を示せ 。但し,&(*p)=100とする 。"); 207 puts("char *p;\np = \"abc\";\n");

(8)

209 char *p; 210 p = "abc";

211 printf("&(*p) = %08x :アドレスを100とする\n",&(*p)); 212 printf("p = %08x\n",p); 213 printf("*p = %c\n",*p); 214 printf("*(p+2) = %c\n\n",*(p+2)); 215 216 puts("A14.p=100,*p=a,*(p+2)=c"); 217 puts("---"); 218 } 219 220 {//Q15 221 puts("---"); 222 puts("Q15.次の文を実行した後の * m、* p、*q の値を示せ 。"); 223 puts("static char m[] = \"abcd\";");

224 puts("char *p, *q;"); 225 puts("p = &m[0];"); 226 puts("q = m;\n"); 227

228 static char m[] = "abcd"; 229 char *p, *q; 230 p = &m[0]; 231 q = m; 232 printf("*m = %c\n",*m); 233 printf("*p = %c\n",*p); 234 printf("*q = %c\n\n",*q); 235 236 puts("A15.*m=a,*p=a,*q=a"); 237 puts("---"); 238 } 239 240 {//Q16 241 puts("---"); 242 puts("Q16.次の文を実行した後の * p、*(m+2)、*m+2 の値を示せ 。"); 243 puts("static char m[] = \"abcd\";");

244 puts("char *p;"); 245 puts("p = &m[2];\n"); 246

247 static char m[] = "abcd"; 248 char *p;

249 p = &m[2];

250 printf("*p = %c\n",*p); 251 printf("*(m+2) = %c\n",*(m+2));

(9)

252 printf("*m+2 = %c\n\n",*m+2); 253 254 puts("A16.*p=c,*(m+2)=c,*m+2=c"); 255 puts("---"); 256 } 257 258 {//Q17 259 puts("---"); 260 puts("Q17.次の文を実行した後のポインタ変数 pの文字列を示せ。"); 261 puts("char *p,q[] = \"abcd\";");

262 puts("p = q;");

263 puts("*(p + 1) = ’x’;\n"); 264

265 char *p,q[] = "abcd"; //bus error 解消のため;

266 p = q; //アクセスが許可されていないメモリにアクセスされるため。 267 *(p + 1) = ’x’;

268 printf("p = %s\n\n",p); 269

270 puts("A17.p = axcd");

271 puts("---"); 272 } 273 274 {//Q18 275 puts("---"); 276 puts("Q18.次の文を実行した後の変数xの値を示せ。"); 277 puts("int x;"); 278 puts("char *p;"); 279 puts("p = \"abcd\";");

280 puts("if(p == \"abcd\") x = 0;"); 281 puts("else x = 1;\n"); 282 283 int x; 284 char *p; 285 p = "abcd"; 286 if(p == "abcd") x = 0; 287 else x = 1; 288 printf("x = %x\n\n",x); 289 290 puts("A18.x = 0"); 291 puts("---"); 292 } 293 294 {//Q19

(10)

295 puts("---");

296 puts("Q19.次の文をポインタの代わりに 、 ”int k;” を宣言し 、配列を用いた文に書き換えよ 。");

297 puts("char m[MAX], *p;"); 298 puts("for(p=m; *p; ++p)"); 299 puts("*p += 1;\n"); 300

301 puts("A19.書き換え後のソースコード(以下に示す)"); 302 puts("int k;");

303 puts("char m[MAX];"); 304 puts("for(k=0;m[k];k++){"); 305 puts("m[k] += 1;"); 306 puts("}"); 307 308 puts("---"); 309 } 310 311 {//Q20 312 puts("---"); 313 puts("Q20.次の定義による,*q[2],q[3][2],*(q[2]+2),*(*(q+3)+2),**(q+1)の値を示せ 。"); 314 puts("static char *q[] = {\"abcd\", \"12345\", \"ABCDEFG\", \"987\"};\n");

315

316 static char *q[] = {"abcd", "12345", "ABCDEFG", "987"}; 317 printf("*q[2] = %c\n",*q[2]); 318 printf("q[3][2] = %c\n",q[3][2]); 319 printf("*(q[2]+2) = %c\n",*(q[2]+2)); 320 printf("*(*(q+3)+2) = %c\n",*(*(q+3)+2)); 321 printf("**(q+1) = %c\n\n",**(q+1)); 322 323 puts("A20.*q[2]=A、q[3][2]=7、*(q[2]+2)= C、*(*(q+3)+2)=7、**(q+1)=1"); 324 puts("---"); 325 } 326 return(0); 327 }

(11)

出力結果と解答 ---Q1.変数 v のアドレスを求める式を示せ。 A1.&v = 5605ab60 ---Q2.1次元配列 m の 0 番目から始まる 5 番目の要素のアドレスを求める式を、2 つ示せ。 A2.&m[5] = 5605aba4 A2.m+5 = 5605aba4 ---Q3.1次元配列 m の先頭アドレスを求める式を、2 つ示せ。 A3.&m[0] = 5605ab5c A3.m[0] = 5605ab5c A3.m = 5605ab5c ---Q4.2次元配列 d の先頭アドレスを求める式を、3 つ示せ。 A4.&d[0][0] = 5605ab58 A4.&d[0] = 5605ab58 A4.d[0] = 5605ab58 A4.*d = 5605ab58 A4.d = 5605ab58 ---Q5.次の文を実行した後の変数 a の値を示せ。 int a=2, b=3, c=5, *p, *q; p = &b; q = &c; a = *p + *q; A5.a = 8 ---Q6.次の文を実行した後の変数 a の値を示せ。 int a=2, *p; p = &a; *p = 5; A6.a = 5

(12)

---Q7.次の文を実行した後の*p、*q、**q の値を示せ。 但し、*(100)=200 -> アドレス 100 の値=200 *(200)=300 -> アドレス 200 の値=300 とする。 int *p, **q,*r; int a=200; int b=300;

p = &a ,q = &r ,r = &b;

(&aをアドレス 100,&b をアドレス 200 と考える) &a = 5605ab0c &b = 5605ab08 *p = 200 *q = 5605ab08 **q = 300 A7.*p=200,*q=5605ab08,**q=300 ---Q8.1次元配列 m において、m[k] と *(m+k) はどのような値か述べよ。 m[0] = 0 *(m+0) = 0 m[1] = 1 *(m+1) = 1 m[2] = 2 *(m+2) = 2 m[3] = 3 *(m+3) = 3 m[4] = 4 *(m+4) = 4 A8.m[k]は配列 m の k 番目の値を示しており,m+k は配列 m の先頭 (0 番目) から k だけ増加し, k番目のアドレスを示すため,*(m+k) では m+k の指す値を示している。 ---Q9.整数型ポインタ変数 p において、p+2 は p の値を何バイト増加させた値か述べよ。 但し、整数型データは 4 バイトとする。 p = a067c5ab p+2 = a067c5b3 A9.8バイト ---Q10.次の文章は正しいか述べよ。 a.1次元配列 m は、*m のようにポインタ変数と同じ書式で使用しても良い。

(13)

b.ポインタ変数 p は、p[0] のように配列名と同じ書式で使用しても良い。 A10(a).正しいと言える。 m[0] => 0,*m => 0 m[1] => 1,*(m+1) => 1 A10(b).正しいと言える。 n[0] => 0,*n => 0 n[1] => 1,*(n+1) => 1 ---Q11.次の定義による,*m,*(m+3),*m+3,*m+*(m+3) の値を示せ。 static int m[5] = {10,20,40,50,30} *m = 10 *(m+3) = 50 *m+3 = 13 *m+*(m+3) = 60 A11.*m=10,*(m+3)=50,*m+3=13,*m+*(m+3)=60 ---Q12.次の定義による,*d[2],*(d[2]+2),*d[2]+2,**d,*(*d+3), **d+6,*(d[1]+2),**(d+2) の値を示せ。 static int d[][3] = {{1,2,3},{5,6,7},{4,6,8},{9,7,5}}; *d[2] = 4 *(d[2]+2) = 8 *d[2]+2 = 6 **d = 1 *(*d+3) = 5 **d+6 = 7 *(d[1]+2) = 7 **(d+2) = 4 A12.*d[2]=4,*(d[2]+2)=8,*d[2]+2=6,**d=1,*(*d+3)=5,**d+6=7,*(d[1]+2)=7,**(d+2)=4 ---Q13.次の文を実行した後のポインタ変数 p の文字列を示せ。 char *str = "abcdefg", *p p = str + 3;

(14)

p = defg A13.p = defg ---Q14.次の文を実行した後の p,*p,*(p+2) の値を示せ。但し,&(*p)=100 とする。 char *p; p = "abc"; &(*p) = 09ba7a4c :アドレスを 100 とする p = 09ba7a4c *p = a *(p+2) = c A14.p=100,*p=a,*(p+2)=c ---Q15.次の文を実行した後の *m、*p、*q の値を示せ。 static char m[] = "abcd";

char *p, *q; p = &m[0]; q = m; *m = a *p = a *q = a A15.*m=a,*p=a,*q=a ---Q16.次の文を実行した後の *p、*(m+2)、*m+2 の値を示せ。 static char m[] = "abcd";

char *p; p = &m[2]; *p = c *(m+2) = c *m+2 = c A16.*p=c,*(m+2)=c,*m+2=c ---Q17.次の文を実行した後のポインタ変数 p の文字列を示せ。

(15)

char *p,q[] = "abcd"; p = q; *(p + 1) = ’x’; p = axcd A17.p = axcd ---Q18.次の文を実行した後の変数 x の値を示せ。 int x; char *p; p = "abcd"; if(p == "abcd") x = 0; else x = 1; x = 0 A18.x = 0 ---Q19.次の文をポインタの代わりに、”int k; ” を宣言し、配列を用いた文に書き換えよ。 char m[MAX], *p; for(p=m; *p; ++p) *p += 1; A19.書き換え後のソースコード (以下に示す) int k; char m[MAX]; for(k=0;m[k];k++){ m[k] += 1; } ---Q20.次の定義による,*q[2],q[3][2],*(q[2]+2),*(*(q+3)+2),**(q+1) の値を示せ。 static char *q[] = {"abcd", "12345", "ABCDEFG", "987"};

*q[2] = A q[3][2] = 7 *(q[2]+2) = C *(*(q+3)+2) = 7 **(q+1) = 1

(16)

A20.*q[2]=A、q[3][2]=7、*(q[2]+2)=C、*(*(q+3)+2)=7、**(q+1)=1 ---考察 1. Q1について,このプログラムでは変数 v のアドレスを出力しており,変数のアドレスを示すために は変数名の前に’&’ を用いている。 2. Q2,3について,指定したアドレスを求める際には&m[n 番目],m+n 番目であり,先頭アドレスは 0 番目を示している。また配列名は配列の要素の先頭アドレスを示しているため,&m[n 番目] と m+n 番目は同じアドレスを示す。 3. Q4について,1 次元配列と同様に配列名は配列の先頭アドレスを示すため,示し方は以下の図のよ うに 5 つとなる。 図 1: Q4 の解説 4. Q5について,ポインタ変数 p,q に変数 b,c のアドレスを代入することで*p と*q に b,c に格納されて いる値をアドレスによって参照し演算を行っている。 5. Q6について,間接参照演算子はアドレスの指す変数を示すため,変数 a は 5 を出力している。以下 図を交えた解説を載せるものとする。 図 2: Q6 の解説

(17)

6. Q7について,整数型変数を宣言しそのアドレスが示す値である 200 と 300 を代入しており,今回の 問題では指定されていないポインタ変数*r を用いているが,これは segmentation fault のエラーを 防ぐために使用している。*p は変数 a を指すため値は 200 となり,*q は r のアドレス (変数 b のア ドレス) を指しているので 200,**q は変数 b を指すため 300 という結果になっている。 7. Q8について,”m[k]”は配列の 0 番目から数えて k 番目の値を示し,”*(m+k)”は先頭アドレスであ る’m’ から k(数値分) だえずらしたアドレスに格納されている値を示すので,どちらの式も同じ値を 示している。 8. Q9について,ポインタ変数では int 型の場合確保されるアドレスの大きさは 4byte であるため p+2 は 8byte 分だけ増加している。また変数の型によって増加する大きさが異なり char 型だと 1byte, double型だと 8byte ずつ増加していく。 9. Q10について,問題 a では配列をポインタ変数の書式を用いて使用することができること,問題 b で はポインタ変数に配列のアドレスを入力し,配列と同様の書式で使用することができることをプログ ラムを用いて証明している。 10. Q11について,静的変数 (static) については第 5 回のレポートにて解説と考察を行っているため割愛 する。”*(m+3)”では配列の先頭アドレスから 3 だけ増加した値を示すため”*(m+3)”は”m[3]”と同 じ値を示す。”*m+3”は”*m”(”m[0]”) の値に 3 を加えた値になり,*m+*(m+3) はこれまでの考察 より,m[0]+m[3] と表せるから m[0] と m[3] を足した値が示される。 11. Q12について,値を求める際の計算過程を以下の図に載せるものとする。(図 3) 図 3: Q12 の計算過程 12. Q13について,ポインタ変数 str には文字列の先頭である’a’ を指すアドレスが代入されているが,ポ インタ変数 p には”str+3”が代入されているため,先頭アドレスに 3 を加えたアドレスが代入されて いることになる。よってポインタ変数 p が指す値は’d’ であり,文字列は NULL 文字までを一つの文 字列として数えるので,ポインタ変数 p の示す文字列は”defg”となる。 13. Q14について,ポインタ変数 p には値’a’ を指すアドレスが代入されており*p は値’a’ を示 す。*(p+2) は先頭アドレスに 2 を加えたアドレスが代入されているので,示す値は’c’ である。

(18)

14. Q15について,”*m”は”m[0]”と表せるから,配列の先頭要素を指している。また”*p”について’p’ に は”m[0]”のアドレスが格納されており,”*q”については’m’ は’m’ 自身の先頭のアドレスを指してい る。よって 3 つの変数の値はすべて’a’ となる。 15. Q16について,’p’ には”m[2]”のアドレスが格納されており,”*(m+2)”は”m[0+2]”と表せ る。”*m+2”に関しては”*m”で配列 m の先頭要素である’a’ を指しているが,ASCII コード表より, 2増加させたときの文字は’c’ となる。よって 3 つの結果が示す値は全て’c’ となる。 16. Q17について,変数を一つ加えているのは,このまま実行すると”bus error”と表示されてしまうた めである。”bus error”とはアクセスが許可されていないメモリにアクセスを行った際に表示される エラーである。”*(p+1)”の要素へ’x’ を格納することで 1 番目の要素を変更している。 17. Q18について,if 文の条件式には文字列を使用することができることがわかる。 18. Q19について,ポインタ変数 p に変わって,int 型変数 k を宣言し,’k’ をインクリメントさせること で配列を操作し,問題文で示されたソースコードと同じ動きをさせている。 19. Q20について,値を求める際の計算過程を以下の図に載せるものとする。(図 4) 図 4: Q20 の計算過程

(19)

2

構造体

2.1

構造体とは

C言語では,複数のデータ型を複数格納することができる箱を作ることができる。配列で格納できるの は単一データのみ (char 型を宣言すると char 型以外は格納することができない) だが,構造体を用いるこ とでバラバラのデータ型を持った変数を一つにまとめることができる。 2.1.1 構造体の宣言 構造体の型の宣言方法は以下の通りになる。 変数を用いる場合は (変数名) の構造体を 1 つ作成し,配列を用いる場合は (変数名) の構造体を (要素数) 個作成する。 struct タグ名 構造体変数名 ([要素数]); { データ型 メンバ名; データ型 メンバ名; データ型 メンバ名; : }; 例えば人のデータをまとめた構造体の定義は以下の図 5 のようになる。 図 5: 人のデータをまとめた構造体 構造体の型を宣言するときは”struct(structure の意味)”を用いる。”struct”をつけることによって,構造 体の型を宣言であることを示しており,また型を置く場所によってローカル変数もしくはグローバル変数 のように有効範囲が変化する。

(20)

2.1.2 構造体の初期化 構造体の初期化を行う際は,変数を用いる時と配列を用いる時では宣言方法が異なる。 変数を用いる際には, struct タグ名 構造変数名 = {データ 1, データ 2, データ 3,…, データ m} と用いて,データ数 m は宣言したメンバ数だけ初期化を行う。 配列を用いる際には struct タグ名 構造体変数名 [要素数] = { {データ 1-1, データ 1-2, データ 1-3,…, データ 1-n}, {データ 2-1, データ 2-2, データ 2-3,…, データ 2-n}, : {データ m-1, データ m-2, データ m-3,…, データ m-n}, } と用いる。 データ数 n は宣言したメンバ数だけ初期化し,データ数 m は要素数の分だけ初期化を行う。 要素分の場所を空白にしておくと,初期化した数が自動で割り当てられるようになる。ただし,初期化 を行う際は,定義した順番に初期化をしなければならない。図 5 に挙げた具体例を用いてソースコードを 書き出すと以下のようになる。 ソースコード 1 //構造体の型宣言 2 struct humanspec{ 3 char name[256]; //名前 4 char sex[256]; //性別 5 int age; //年齢 6 int height; //身長 7 int weight; //体重 8 }; 9 10 //構造体の宣言と初期化の代入

11 struct humanspec humanspec[200] = { 12 {学籍番号,氏名,学年,クラス}, 13 {学籍番号,氏名,学年,クラス}, 14 {学籍番号,氏名,学年,クラス},

(21)

15 {学籍番号,学年,氏名,クラス} //定義した順番でないとエラーになる 16 }; 2.1.3 構造体のデータ参照 構造体に格納したデータを変数に代入する際は以下のように参照する。 変数 = 構造体変数名. メンバ名;(変数を用いた場合) 変数 = 構造体変数名 [要素数]. メンバ名;(配列を用いた場合) 構造体変数名とメンバ名の間に.(ピリオド) があり,このピリオドをドット演算子と呼び,構造体を参照 する際に用いる。ここまでの構造体の仕組みについてをまとめた例文を以下に示す。 ソースコード 1 #include <stdio.h> 2 3 struct e1557XX{ 4 int number; //学籍番号 5 char *name; //名前 6 char sex; //性別 7 }; 8 9 int main(){ 10 int i = 0; 11 printf("学籍番号\t 名前\t性別\n"); 12

13 struct e1557XX meibo[10] = { 14 {155701,"中野梓",’F’}, 15 {155702,"東横桃子",’F’}, 16 {155703,"小鳥遊六花",’F’}, 17 {155704,"五更瑠璃",’F’}, 18 {155705," 美樹さやか",’F’}, 19 {155706,"S・デュノア",’F’}, 20 {155707,"長門有希",’F’}, 21 {155708,"岩崎みなみ",’F’}, 22 {155709,"西園美魚",’F’}, 23 {155710,"藤原文太",’M’}, 24 }; 25 26 for(i=0;i<10;i++){

(22)

27 printf("%8d%17s%5c\n",meibo[i].number,meibo[i].name,meibo[i].sex); 28 } 29 return(0); 30 } 出力結果 学籍番号 名前 性別 155701 中野梓 F 155702 東横桃子 F 155703 小鳥遊六花 F 155704 五更瑠璃 F 155705 美樹さやか F 155706 S・デュノア F 155707 長門有希 F 155708 岩崎みなみ F 155709 西園美魚 F 155710 藤原文太 M (便宜上,出力結果に改変を加えている)

2.2

構造体とポインタ

2.2.1 ポインタを用いた構造体の宣言 構造体変数も通常の変数と同様にポインタを使用することができる。ポインタを用いて構造体の宣言を 行うためには構造体変数名にポインタ変数同様’*’ をつけることによりポインタ構造体変数として使用する ことができる。 struct タグ名 *構造体変数名; ポインタ構造体変数も変数に値を入れることが可能であるが,構造体変数のアドレスをポインタ構造体 変数に代入するときには以下のように注意しなければならない。 変数を用いた構造体 ポインタ構造体変数名 = &構造体変数名;(struct タグ名 *構造体変数名 で宣言)

(23)

構造体を変数を用いて宣言した時は,普通の変数を宣言した時と同じように 1 つの構造体変数として扱 われ,printf 関数で出力すると構造体の型の最初に定義したメンバの値が出力される。これより,ポインタ でないため’&’ を用いてアドレスを意味する。 配列を用いた構造体 ポインタ構造体変数名 = 構造体変数名; 構造体を配列を用いて宣言した時は,普通の配列を宣言した時と同じように構造体配列として扱われ,配 列で宣言した変数は配列の先頭アドレスを指す。これより,ポインタであるため’&’ を付ける必要がない。 2.2.2 ポインタ構造体のデータ参照 ポインタ構造体に格納した値を変数に代入するときには以下のように参照する。 変数 = ポインタ構造体変数名->メンバ名; ポインタ構造体の場合では,ポインタ構造体変数とメンバ名の間に”->”がある。”->”をアロー演算子と 呼び,ポインタ構造体を参照する際に使用する。普通の構造体の際には’.’(ピリオド),ポインタ構造体の際 には”->”(アロー) を用いるので注意する必要がある。ここまでのポインタ構造体変数の仕組みについてを まとめた例文を以下に示す。 ソースコード 1 #include <stdio.h> 2 3 struct e1557XX{ 4 int number; //学籍番号 5 char *name; //名前 6 char sex; //性別 7 }; 8 9 int main(){ 10 int i = 0; 11 printf("学籍番号\t 名前\t性別\n"); 12

13 struct e1557XX meibo[10] = { 14 {155701,"中野梓",’F’}, 15 {155702,"東横桃子",’F’},

(24)

16 {155703,"小鳥遊六花",’F’}, 17 {155704,"五更瑠璃",’F’}, 18 {155705," 美樹さやか",’F’}, 19 {155706,"S・デュノア",’F’}, 20 {155707,"長門有希",’F’}, 21 {155708,"岩崎みなみ",’F’}, 22 {155709,"西園美魚",’F’}, 23 {155710,"藤原文太",’M’}, 24 }; 25 26 struct e1557XX *p; //構造体のポインタ宣言 27 p = meibo; //ポインタ p に構造体 meibo の先頭アドレスを代入 28 29 for(i=0;i<10;i++){

30 printf("%8d%17s%5c\n",(p+i)->number,(p+i)->name,(p+i)->sex); 31 } 32 return(0); 33 } 出力結果 学籍番号 名前 性別 155701 中野梓 F 155702 東横桃子 F 155703 小鳥遊六花 F 155704 五更瑠璃 F 155705 美樹さやか F 155706 S・デュノア F 155707 長門有希 F 155708 岩崎みなみ F 155709 西園美魚 F 155710 藤原文太 M (便宜上,出力結果に改変を加えている)

(25)

2.3

関数と構造体

構造体は関数の引数としても用いることができ,以下のようにして構造体を関数に渡す。 関数名 (構造体変数 or ポインタ構造体変数); //戻り値を持たない 値 = 関数名 (構造体変数 or ポインタ構造体変数) //戻り値を持つ 戻り値を持たない場合は自作関数の引数を構造体で宣言し,戻り値を保つ場合には自作関数の戻り値の 型を構造体で宣言しなければならない。また’&’ を付けない構造体変数の場合は値渡し,’&’ をつけた構造 体変数とポインタ構造体変数の場合は参照渡しとなる。 int型の変数の値を関数の引数として渡すと,その int 型の値が 1 つ引数として渡される。一方,構造体 を関数の引数として渡すと,構造体に含まれる個々のメンバの値が全て渡される。したがって,構造体に 含まれるメンバの数が多いと,1 個の引数を渡しているように見えるが,実際は多数の値が関数に渡される ことになる。 値渡しは全ての値をコピーして関数に渡すため,コピーする時間が生じてしまい処理が遅くなる。一方, 参照渡しは配列や構造体の先頭アドレスを渡すだけで良いため,値渡しに比べて格段に処理が早くメモリ 消費も少なくなる。

3

あとがき

今回のレポートは問題の解説と考察ということで,いつもと少し違った感じのレポートになりました。 手抜きみたいな感じがしてあんまりレポートを書いた感じがしないのが正直な感想です。構造体の基本的 なところも復習することができましたので,最後のレポートもしっかり取り組んでいきたいと思います。

参考文献

[1] C実践プログラミング — Steve Oualline 著, 望月 康司 監訳, 谷口 功 訳 [2] 納得 C 言語 — http://www.isl.ne.jp/pcsp/beginC/

参照

関連したドキュメント

劣モジュラ解析 (Submodular Analysis) 劣モジュラ関数は,凸関数か? 凹関数か?... LP ニュートン法 ( の変種

不変量 意味論 何らかの構造を保存する関手を与えること..

前章 / 節からの流れで、計算可能な関数のもつ性質を抽象的に捉えることから始めよう。話を 単純にするために、以下では次のような型のプログラム を考える。 は部分関数 (

実際, クラス C の多様体については, ここでは 詳細には述べないが, 代数 reduction をはじめ類似のいくつかの方法を 組み合わせてその構造を組織的に研究することができる

(問5-3)検体検査管理加算に係る機能評価係数Ⅰは検体検査を実施していない月も医療機関別係数に合算することができる か。

これはつまり十進法ではなく、一進法を用いて自然数を表記するということである。とは いえ数が大きくなると見にくくなるので、.. 0, 1,

・逆解析は,GA(遺伝的アルゴリズム)を用い,パラメータは,個体数 20,世 代数 100,交叉確率 0.75,突然変異率は

機器表に以下の追加必要事項を記載している。 ・性能値(機器効率) ・試験方法等に関する規格 ・型番 ・製造者名