構造体(ポインタ変数)のコンパイラ間の差
―更新準備中―
構造体のポインタ変数の扱いについては、コンパイラによって結構差があるところなので、
あのコンパイラでは通ったソースコードが別のコンパイラではエラーが出るというようなことが
あります。
今回、コンパイラ間の差を試してみました。
各プログラムの説明は「構造体(ポインタ変数)」をご参照下さい。
このページは各コンパイラ間の差についてのみ説明しています。
T 構造体のポインタ変数とメンバーの参照
構造体のポインタ変数への値の入力と参照のプログラムです。
構造体の各メンバー、name,adress,telに値の入力をした後に、3パターンの方法で各メンバーの
値を参照して表示しています。
structa.c for Borland C++用
(LSIC-86でコンパイルもOK)
#include <stdio.h> struct personal { char name[20]; char adress[40]; char tel[15]; }; int main(void){ struct personal *ps, ps_data[2]; /* (1) */ int i; /* 下の ps=ps_data; がないと、コンパイル時に「PSの値が未定義」というエラーになる*/ ps=ps_data; /* (2) */ for(i=0;i<2;i++,ps++){ /* (3) */ printf("name? -"); gets(ps->name); printf("adress? -"); gets(ps->adress); printf("tel? -"); gets(ps->tel); printf("\n"); } ps=ps_data; /* (4) */ for(i=0;i<2;i++){ printf("%s : %s : %s\n",(*(ps+i)).name,(*(ps+i)).adress,(*(ps+i)).tel);} ps=ps_data; for(i=0;i<2;i++){ printf("%s : %s : %s\n",(ps+i)->name,(ps+i)->adress,(ps+i)->tel);} ps=ps_data; for(i=0;i<2;i++,ps++){ printf("%s : %s : %s\n",ps->name,ps->adress,ps->tel);} return 0; } |
C:\C>structa name? -田中 adress? -東京都世田谷区 tel? -999-666-333 name? -Ron Bon adress? -NY, US tel? -777-999-999 田中 : 東京都世田谷区 : 999-666-333 Ron Bon : NY, US : 777-999-999 田中 : 東京都世田谷区 : 999-666-333 Ron Bon : NY, US : 777-999-999 田中 : 東京都世田谷区 : 999-666-333 Ron Bon : NY, US : 777-999-999 C:\C> |
personal構造体の各メンバ変数を配列からポインタ変数に変更してみた。
LSIC-86でコンパイルしたものは動作するが、
Borand C++, Visual C++ でこのソースコードをコンパイルしたプログラムはデータの入力の途中で動作を停止し
プログラムが終了してしまう。
#include <stdio.h> struct personal { char *name; char *adress; char *tel; }; int main(void){ struct personal *ps, ps_data[2]; int i; /* 下の ps=ps_data; がないと、コンパイル時に「PSの値が未定義」というエラーになる*/ ps=ps_data; for(i=0;i<2;i++,ps++){ /* Borland C++では2周目に動作停止 */ printf("name? -"); gets(ps->name); printf("adress? -"); gets(ps->adress); printf("tel? -"); gets(ps->tel); printf("\n"); } ps=ps_data; for(i=0;i<2;i++){ printf("%s : %s : %s\n",(*(ps+i)).name,(*(ps+i)).adress,(*(ps+i)).tel); } ps=ps_data; for(i=0;i<2;i++){ printf("%s : %s : %s\n",(ps+i)->name,(ps+i)->adress,(ps+i)->tel); } ps=ps_data; for(i=0;i<2;i++,ps++){ printf("%s : %s : %s\n",ps->name,ps->adress,ps->tel); } return 0;}
U 構造体のコピー(代入)
int型のメンバー変数x,yをもつstarという型の構造体を作って、3つのやり方で構造体変数のコピー(代入)を
してみます。
struct3a.c
Borland C++, Visual C++でコンパイル可。
#include <stdio.h> struct star{ int x; int y; }; int main(void) { struct star st, *p,q; /* @ */ st.x=100; st.y=200; q=st; /* A */ printf("q:%d st:%d \n",&q,&st); printf("q.x:%d, q.y:%d\n",q.x,q.y); st.x=1; st.y=2; *p=st; /* B */ printf("p:%d st:%d \n",p,&st); printf("p->x:%d, p->y:%d\n",p->x,p->y); st.x=-5; st.y=0; /* C */ printf("st.x:%d, st.y:%d, p->x:%d, p->y:%d\n",st.x,st.y,p->x,p->y); st.x=10; st.y=15; p=&st; /* D */ printf("p:%d &st:%d \n",p,&st); printf("p->x:%d, p->y:%d\n",p->x,p->y); st.x=0; st.y=50; /* E */ printf("st.x:%d, st.y:%d, p->x:%d, p->y:%d\n",st.x,st.y,p->x,p->y); return 0; }
LSIC-86でコンパイルすると、Bの個所で、pのアドレスが定まっていないという警告がでる。
そのままコンパイルはできてしまうので、コンパイルして実行した結果
V 構造体を関数で受け渡し
構造体の変数を関数の引数として渡すプログラムです。
A、Bは表示のための関数ですが、Aは構造体のポインタ変数を使って、Bは構造体変数を使って引数を
受け渡ししています。
struct2b.c Borland C++用
#include <stdio.h> void input(struct personal *); void display(struct personal *); void display2(struct personal); struct personal { char name[20]; char adress[40]; char tel[15]; }; int main(void){ struct personal ps_data[2]; input(ps_data); display(ps_data); display2(ps_data[0]); return 0; } void input(ps) /* @ */ struct personal * ps {int i; for(i=0;i<2;i++,ps++){ printf("name? -"); gets(ps->name); printf("%s\n",ps->name); printf("adress? -"); gets(ps->adress); printf("%s\n",ps->adress); printf("tel? -"); gets(ps->tel); printf("%s\n",ps->tel);} } void display(ps) /* A */ struct personal *ps; {int i; for(i=0;i<2;i++,ps++){ printf("%s : %s : %s\n",ps->name,ps->adress,ps->tel);} } void display2(ps) /* B */ struct personal ps; { printf("%s : %s : %s\n",ps.name,ps.adress,ps.tel);} |
c:\bcc55\Bin>struct2b name? -Yamada Taro Yamada Taro adress? -Nerima-Ku, Tokyo, Japan Nerima-Ku, Tokyo, Japan tel? -999-333-1234 999-333-1234 name? -John Bonn John Bonn adress? -NY, US NY, US tel? -000-000-0000 000-000-0000 Yamada Taro : Nerima-Ku, Tokyo, Japan : 999-333-1234 John Bonn : NY, US : 000-000-0000 Yamada Taro : Nerima-Ku, Tokyo, Japan : 999-333-1234 c:\bcc55\Bin> |
struct2b.c Visual C++2022用
最近のVisual C++はセキュリティ上の問題からgetsが使用禁止になっているので、
代わりにgets_sを使っている。
#include <stdio.h> void input(struct personal*); void display(struct personal*); void display2(struct personal); struct personal { char name[20]; char adress[40]; char tel[15]; }; int main(void) { struct personal ps, ps_data[2]; input(ps_data); display(ps_data); display2(ps_data[0]); return 0; } void input(struct personal* ps) { int i; for (i = 0; i < 2; i++, ps++) { printf("name? -"); gets_s(ps->name,20); printf("%s\n", ps->name); printf("adress? -"); gets_s(ps->adress,40); printf("%s\n", ps->adress); printf("tel? -"); gets_s(ps->tel,15); printf("%s\n",ps->tel); } } void display(ps) struct personal* ps; {int i; for (i = 0; i < 2; i++, ps++) { printf("%s : %s : %s\n", ps->name, ps->adress, ps->tel); }} void display2(ps) struct personal ps; { printf("%s : %s : %s\n", ps.name, ps.adress, ps.tel); }
LSIC-86
personal型の構造体の定義で、メンバー変数を配列ではなくポインタ変数にしてみた。
Borland C++やVisual C++でコンパイルすると、input関数で値を入力するところでプログラムが
停止してしまうが、LSIC-86でコンパイルするとちゃんと動作する。
ただし、LSIC-86では関数display2はpersonalが未定義というエラーが出る。
関数の引数として構造体変数を引き渡すときには、構造体のポインタ変数しか引き渡せない
(つまり参照渡しで引き渡すしかない)
struct2.c LSIC-86用
#include <stdio.h> void input(struct personal *); void display(struct personal *); /* void display2(struct personal); これはpersonalが未定義というエラーがでる*/ struct personal { char *name; char *adress; char *tel; }; int main(void){ struct personal ps_data[2]; input(ps_data); display(ps_data); /* display2(ps_data[0]); */ return 0; } void input(ps) struct personal *ps; {int i; for(i=0;i<2;i++,ps++){ printf("name? -"); gets(ps->name); printf("adress? -"); gets(ps->adress); printf("tel? -"); gets(ps->tel); printf("\n"); }} void display(ps) struct personal *ps; {int i; for(i=0;i<2;i++,ps++){ printf("%s : %s : %s\n",ps->name,ps->adress,ps->tel); }} /* void display2(ps) struct personal ps; {printf("%s : %s :%s\n",ps.name,ps.adress,ps.tel);} */
mallocでメモリを動的に確保
personal型の構造体の定義で、メンバー変数を配列ではなくポインタ変数にしてみた場合、
mallocで動的にメモリを確保すれば、Borland C++でコンパイルしてもちゃんと動作する。
bufに入力された文字列は、strcpyを使って、各メンバ変数 ps->name, ps->adress,
ps->tel
にコピーする。
struct2a.c Borland C++用
#include <stdio.h> void input(struct personal *); void display(struct personal *); /* void display2(struct personal); */ struct personal { char *name; char *adress; char *tel; }; int main(void){ struct personal ps_data[2]; input(ps_data); display(ps_data); /* display2(ps_data[0]); */ return 0; } void input(struct personal * ps) {int i; char *buf; for(i=0;i<2;i++,ps++){ printf("name? -"); gets(buf); ps->name=malloc(strlen(buf)+1); strcpy(ps->name,buf); printf("%s\n",ps->name); printf("adress? -"); gets(buf); ps->adress=malloc(strlen(buf)+1); strcpy(ps->adress,buf); printf("%s\n",ps->adress); printf("tel? -"); gets(buf); ps->tel=malloc(strlen(buf)+1); strcpy(ps->tel,buf); printf("%s\n",ps->tel); }} void display(ps) struct personal *ps; {int i; for(i=0;i<2;i++,ps++){ printf("%s : %s : %s\n",ps->name,ps->adress,ps->tel); }} /* void display2(ps) struct personal ps; {printf("%s : %s :%s\n",ps.name,ps.adress,ps.tel);} */