構造体(ポインタ変数)のコンパイラ間の差
―更新準備中―
構造体のポインタ変数の扱いについては、コンパイラによって結構差があるところなので、
あのコンパイラでは通ったソースコードが別のコンパイラではエラーが出るというようなことが
あります。
今回、コンパイラ間の差を試してみました。
各プログラムの説明は「構造体(ポインタ変数)」をご参照下さい。
このページは各コンパイラ間の差についてのみ説明しています。
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);}
*/