ページ 1 / 1
配列、構造体、ポインタの問題です。
Posted: 2013年6月21日(金) 20:37
by こにし
ポインタを使った構造体の問題で質問です。
問題:3人分の、名前、年齢、性別、を入力して表示するプログラムを作りなさい。
ただし、データは構造体で記憶することとし、
また、データの入力と表示はそれぞれ専用の関数を作って行うこととする。
自分はこのように書きました。
コード:
#include<stdio.h>
#include<string.h>
struct member
{
char name[64];
int age;
int sex;
};
void n(member *data);
void s(member *data);
int main(void)
{
struct mamber data[3];
void n(&data);
void s(&data);
return 0;
}
void n(member *data)
{
int i:
for(i=0;i<=2;i++)
{
printf("名前は?");
scanf("%s%*c",data[0]->name);//ポインタなので、->を使っています。
printf("年齢は?");
scanf("%d",&data[i]->age);
printf("性別は?1-男、2-女");
scanf("%d",&data[i]->sex);
}
}
void s(member *data)
{
int i;
char sex[16];
for(i=0;i<=2;i++)
{
printf("%s",data[i]->name);
printf("%d",data[i]->age);
if(data[i]->sex==1)
{
strcpy(sex,"男");
}
else
{
strcpy(sex,"女");
}
printf("%s",sex);
}
}
しかし、8行目に、, が抜けていますとエラーがでて、うまくいきません。どうすればうまくいくのでしょうか?
お力を貸していただけないでしょうか。
よろしくお願いします。
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月21日(金) 20:49
by softya(ソフト屋)
これは、ご自分で考えられたのでしょうか? C++の文法が混じっているようですが。
あとインデント(字下げ)をしていないので大変読みづらいです。
※ 他にも色々と問題があります。
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月21日(金) 20:53
by こにし
ご回答ありがとうございます。
これは問題集の解説を参考にし、自分で考えて作りました。
字下げをし忘れてしまったことは、大変失礼しました。
今後そのようなことがないように気をつけます。
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月21日(金) 20:55
by こにし
たくさん間違えている部分があるということですね。
午後ずっと考えて、参考書なども使いながら考えたのですが、どうしてもわかりませんでした。
すみませんが、少し教えていただけないでしょうか?
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月21日(金) 20:59
by こにし
この問題は、苦しんで覚えるC言語という本の問題です。回答例は次のようになっています。
コード:
#include <stdio.h>
#include <string.h>
typedef struct {
char name[256];
int age;
int sex;
} People;
void InputPeople(People *data);
void ShowPeople(People data);
int main(void)
{
People data[3];
int i;
for (i = 0;i < 3;i++) {
InputPeople(&data[i]);
}
for (i = 0;i < 3;i++) {
ShowPeople(data[i]);
}
return 0;
}
void InputPeople(People *data)
{
printf("名前:");
scanf("%s",data->name);
printf("年齢:");
scanf("%d",&data->age);
printf("性別(1-男性、2-女性):");
scanf("%d",&data->sex);
printf("\n");
}
void ShowPeople(People data)
{
char sex[16];
printf("名前:%s\n",data.name);
printf("年齢:%d\n",data.age);
if (data.sex == 1) {
strcpy(sex,"男性");
} else {
strcpy(sex,"女性");
}
printf("性別:%s\n",sex);
printf("\n");
}
そして、それ以外に猫にでもわかるC言語で構造体のポインタ、配列を学びました。
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月21日(金) 21:06
by softya(ソフト屋)
全部見直しましたが、C++を参考にしたのではなく単に間違えたのかと思いますので、問題点を書いておきますね。
・構造体名はstructを必ずつけてください。関数の定義で間違っています。
・構造体名を間違えている所があります。
・関数の宣言と呼び出しが混同されています。void n( &data );など。
・ポインタと配列の理解が曖昧な所があります。そのため扱いを間違っています。
void n( &data );
data[0]->name
などは間違いです。
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月21日(金) 21:14
by こにし
ありがとうございます。
ご指摘していただいた点を直しました。
①構造体名はstructを必ずつけてください。
void n(member *data);
→void n(struct member *data);
②構造体名を間違えている所があります。
struct mamber data[3];
→struct member data[3];
③関数の宣言と呼び出しが混同されています。void n( &data );など。
・ポインタと配列の理解が曖昧な所があります。そのため扱いを間違っています。
void n( &data );
data[0]->name
などは間違いです。
すみません。③番はわかりませんでした。
今自分がわかっているのは、配列a[0]は配列aのアドレスを示すことです。
今回、struct mamber data[3];
より配列なので
void n( &data );
→void n(data );となる。
という理解でよろしいのでしょうか?
初歩的な質問ですみません。
よろしくお願いします。
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月21日(金) 21:16
by Hiragi(GKUTH)
いろいろな人が見ると思うのでひとまずインデントをつけてみました
コード:
#include<stdio.h>
#include<string.h>
struct member
{
char name[64];
int age;
int sex;
};
void n(member *data);
void s(member *data);
int main(void)
{
struct mamber data[3];
void n(&data);
void s(&data);
return 0;
}
void n(member *data)
{
int i:
for(i=0;i<=2;i++)
{
printf("名前は?");
scanf("%s%*c",data[0]->name);//ポインタなので、->を使っています。
printf("年齢は?");
scanf("%d",&data[i]->age);
printf("性別は?1-男、2-女");
scanf("%d",&data[i]->sex);
}
}
void s(member *data)
{
int i;
char sex[16];
for(i=0;i<=2;i++)
{
printf("%s",data[i]->name);
printf("%d",data[i]->age);
if(data[i]->sex==1)
{
strcpy(sex,"男");
}
else
{
strcpy(sex,"女");
}
printf("%s",sex);
}
}
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月21日(金) 21:19
by こにし
Hiragiさん、本当にありがとうございます。
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月21日(金) 21:22
by softya(ソフト屋)
(3)・関数の宣言と呼び出しが混同されています。void n( &data );など。
(4)・ポインタと配列の理解が曖昧な所があります。そのため扱いを間違っています。
void n( &data );
data[0]->name
などは間違いです。
で別件です。
(3)は、voidの意味は理解されていますか? あと使いどころは何処でしょうか?
(4)は、配列とポインタの互換性と言うか、配列のポインタの様に扱える時はどういう時ですか?
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月21日(金) 21:35
by Hiragi(GKUTH)
(3)のヒント、
printfやscanfも関数ですが呼び出すときにいちいち
int printf("HelloWorld");
とかなんてしないですよね?それは返り値がない時や自分で作った関数でも同じです、つまり・・・?
(4)のヒント、
>今自分がわかっているのは、配列a[0]は配列aのアドレスを示すことです。
ということは 今回の場合
data[0] は 構造体data のポインタとほぼ同じ意味を持つから、
呼び出しの時に n(&data)としてしまうと・・・?
追記:コレを見て考えていたことがわけわからなくなっちゃったり
余計にわからなくなったりするのであれば無視してOKです。
思ったことをあまり考えずに一度言ってみたりしても案外解決したりするかもしれません
間違っていたりしたらどうしようって思って投稿するのにもうちょっと考えてみようとかするかもしれませんが(俺がそうだった
間違っていると分かったらいいこともあると思います。
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月21日(金) 21:40
by こにし
voidというのは、たとえば、void main()だった場合、戻り値を必要としないか、またポインタを関数内で使うことで、戻り値を使わなくても値を変更できることです。
また、int main(void)の場合、main関数に何も代入しないことを表しています。
4は、たとえば、scanfの場合、配列の最初がアドレスを示すので、&を必要としないこと。また、たとえば、char *str; str="abc";となる場合、*(str+i)=strとなります。
です。よろしくお願いします。
ヒントありがとうございます。
(3)ということはvoidは省略ですね! 確かにintなどは省略するのに、voidだけ省略しないのはおかしいですよね。
(4)のヒントはわかりませんでした。ただ、&をつけることで、%pでアドレスがわかることはわかります。
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月21日(金) 21:45
by softya(ソフト屋)
(3)に関しては、 関数の宣言、定義、呼び出しの3つ違いを調べてみてください。
(4)に関しては、基本の所はなんとなく理解されているようですが根本的な理解が不足しているようです。
引数にする場合に配列と配列ではない変数・構造体では大きく違うところがあります。
これに関して、ポインタ渡しと値渡しの違いも調べてみてください。苦Cにも書いてあるはずです。
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月21日(金) 22:05
by こにし
ポインタ渡しと値渡しはわかります。
ポインタ渡しはアドレス内の値をポインタを使って直接変えること。
値渡しは値のコピーを変更することです。
>引数にする場合に配列と配列ではない変数・構造体では大きく違うところがあります。
これがまったくわかりません。いろいろ調べてみようと思います。
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月21日(金) 22:18
by softya(ソフト屋)
こにし さんが書きました:ポインタ渡しと値渡しはわかります。
ポインタ渡しはアドレス内の値をポインタを使って直接変えること。
値渡しは値のコピーを変更することです。
その説明では何かが違います。
△ ポインタ渡しはアドレス内の値をポインタを使って直接変えること。 → ポインタの使い方として何か説明が変です。
X 値渡しは値のコピーを変更することです。 → 必ず変更するんでしょうか?
引数の値渡しとポインタ渡しの関数の呼び出し元から呼び出し先までの動作と、それぞれのメリットとデメリットを出来るだけ書いてみてください。
【補足】 混乱させるヒント書くとC言語には実は値渡ししかありません。ポインタ渡しというのは、ポインタも変数でありポインタ値を値渡ししているのです。
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月21日(金) 22:25
by こにし
すみません、そこまではわかりません。
テキストは何周かしたのですが、全然上手くかけません。説明もできませんし・・・
まだまだ復習、勉強が必要なようです。
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月21日(金) 22:28
by softya(ソフト屋)
じゃあ、関数における仮引数と実引き数の関係というか値渡しで分かっていることを書いてみてください。
あと、色んなパターンを書いてデバッガで追いかけてみるとか、ポインタ値をprintfしてみるとかもしたことないですか?
【補足】 ポインタについて
ポインタは変数です。 ※ ここ重要。
int型が数値を代入できるように、ポインタ型にはポインタ値が代入できます。
ポインタ値は、変数や構造体の実体を指し示しめすのに使います。 ※ ここが特殊。
NULLの場合は、どこも指し示していない状態を表します。
不定なポインタ値の場合は、そのポインタ値を使って指し示す先を操作した場合どんな動作をするか保証されていません。
ただしいポインタ値なら指し示す先の変数や構造体の値を参照・変更できます。
と簡単な説明でした。
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月21日(金) 22:54
by こにし
書いてみました。
コード:
#include<stdio.h>
int func(int a);
int main(void)
{
int a=10;
printf("aの値は%dです\n",a);
func(a);
return 0;
}
int func (int a)
{
a=15;
printf("aの値は%dです。\n",a);
}
コード:
#include<stdio.h>
void func(int a);
int main(void)
{
int a,*b;
b=&a;
*b=10;
printf("aの値は%dです\n",a);
func(a);
printf("aの値は%dです。\n",a);
return 0;
}
void func (int a)
{
a=15;
}
などです。
今思いついたのが、これらです。
よろしくお願いします。
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月21日(金) 22:59
by softya(ソフト屋)
1つ前の補足も読んでみてくださいね。
で、(1)or(2)のプログラムで、mainのaとfuncのaのポインタ値をprintfしてみてください。書式は%pを使います。
どうですか、何か分かりますか?
【追記】 そうだ。関数を呼び出すときの実引数は式なので、計算式を書いてみましょう。
それと、構造体の値渡しをやってみてください。 ※ ポインタは使いません。
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月21日(金) 23:22
by ISLe
苦Cを参考にしているなら、ポインタの説明も苦Cに沿ったものにしないと混乱するのではないでしょうか。
何とかモードみたいな。
その場しのぎにしかならないですが。
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月21日(金) 23:24
by こにし
補足ありがとうございます。
ひとつ質問なのですが、
>ポインタ値は、変数や構造体の実体を指し示しめすのに使います。
実体とは、その変数、構造体のアドレスのことでしょうか?
まことに申し訳ありませんが、今外出先で、苦Cの総合環境を使ってプログラミングしているのですが、実行するとウイルスと認識され、上手く実行できない状態にあります。申し訳ございませんが、実行していただけないでしょうか?
コード:
#include<stdio.h>
int func(int a);
int main(void)
{
int a=10;
printf("aは%pです\n",a);
func(a);
return 0;
}
int func (int a)
{
a=15;
printf("aは%pです。\n",a);
}
です。本当に申し訳ないです。
実行が上手くいくかわかりませんが、書きます。
コード:
#include<stdio.h>
struct student
{
int age;
};
void func(k);
int main(void)
{
struct student data;
data.age=18;
printf("年齢は%dです。"data.age);
func(struct student data);
return 0;
}
void func(k)
{
k=10;
printf("年齢は%dです。",k);
}
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月21日(金) 23:30
by こにし
最後のプログラム間違えていますね。
コード:
#include<stdio.h>
struct student
{
int age;
};
void func(struct student data);
int main(void)
{
struct student data;
data.age=18;
printf("年齢は%dです。"data.age);
func(struct student data);
return 0;
}
void func(struct student data)
{int age;
data.age=10;
printf("年齢は%dです。",data.age);
}
これでも間違えですが、さきほどよりは正解に近くなったと思います。
もうよくわからなくなってきました・・・
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月21日(金) 23:39
by softya(ソフト屋)
実は間違っているのですが、実行してみました。
「Ideone.com | Online C Compiler & Debugging Tool」
http://ideone.com/4MdTQV
ここを使えばWEBに接続出来れば実行出来ます。
aをprintfしてますが、aのポインタ値は&aです。
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月21日(金) 23:43
by こにし
ネットでも実行できるのですね。
ありがとうございます。
わかったのは、アドレスが違うことですね。また、&aがアドレス値になっているわけですね。
アドレスが違うならば、aは同じでも違う変数ということになりますね。
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月21日(金) 23:55
by softya(ソフト屋)
>>ポインタ値は、変数や構造体の実体を指し示しめすのに使います。
> 実体とは、その変数、構造体のアドレスのことでしょうか?
いえ、アドレスではありません。変数、構造体そのもの事です。
ポインタ値は、大抵のコンパイラの場合アドレスですがC言語の規格上はアドレスであると決められているわけではありません。
「アドレスとポインタの違い | 株式会社きじねこ」
http://www.kijineko.co.jp/node/498
なので、ここの人たちはアドレスという言葉を避けています。
あとアドレスという言葉に惑わされて混乱する人も沢山います。
なので、ポインタ値は変数、構造体の実体を指し示すものなのです。
それじゃあ、ちょっといじってこれは理解出来ますか?
「Ideone.com | Online C Compiler & Debugging Tool」
http://ideone.com/YQhBxc
構造体の値渡しは盛大に間違っているので、それこそ宣言方法から調べてみましょう。
これを理解したら、ポインタに進みましょう。 私が12:30ごろには寝るので、今日は最期までやるのは難しいかもしれませんが・・・。
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月21日(金) 23:58
by softya(ソフト屋)
おまけ、更に複雑なパターン。
「Ideone.com | Online C Compiler & Debugging Tool」
http://ideone.com/OE1DTX
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月22日(土) 00:06
by こにし
丁寧に教えてくださり、ありがとうございます。
http://ideone.com/YQhBxc
は理解できました。
関数内のaは値を変えても、ある場所が変わるわけではないのでアドレスは変わりません。という考えであっているでしょうか?
そうですね。構造体の値渡しはやらないといけないですね。
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月22日(土) 00:09
by こにし
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月22日(土) 00:11
by softya(ソフト屋)
こにし さんが書きました:丁寧に教えてくださり、ありがとうございます。
http://ideone.com/YQhBxc
は理解できました。
関数内のaは値を変えても、ある場所が変わるわけではないのでアドレスは変わりません。という考えであっているでしょうか?
そうですね。構造体の値渡しはやらないといけないですね。
式で計算しても元のaは変わりませんが、呼び出した先のaには計算後の値が入っているって所です。
オマケ版も見ておいてくださいね。
ちなみに構造体版は、
関数の宣言と定義、呼び出しと間違っています。
もしかして、構造体代入自体を未経験でしょうか?それと考え方は同じなのですが。
あっていますが、構造体代入が分かっていないならやっておいたほうが良いです。
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月22日(土) 00:23
by こにし
コード:
#include<stdio.h>
#include<string.h>
void func(struct student a);
struct student
{
int age;
char name;
};
int main(void)
{
struct student data;
data.age=18;
strcpy(data.name,"abcd");
printf("名前は%sで、年齢は%d",data.name,data.age);
func(data);
return 0;
}
void func(struct student a)
{
a.age=20;
strcpy(a.name,"efgh");
printf("名前は%sで、年齢は%d",a.name,a.age);
}
これは上手くいっているでしょうか?すみません、ネットで起動できるサイトの使い方がわかりませんでした。早急に覚えます。
オマケ版も理解できています。再度見てみます。
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月22日(土) 00:25
by こにし
できました!
コード:
#include<stdio.h>
#include<string.h>
void func(struct student a);
struct student
{
int age;
char name[64];
};
int main(void)
{
struct student data;
data.age=18;
strcpy(data.name,"abcd");
printf("名前は%sで、年齢は%d",data.name,data.age);
func(data);
return 0;
}
void func(struct student a)
{
a.age=20;
strcpy(a.name,"efgh");
printf("名前は%sで、年齢は%d",a.name,a.age);
}
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月22日(土) 00:27
by こにし
できました!
コード:
#include<stdio.h>
#include<string.h>
void func(struct student a);
struct student
{
int age;
char name[64];
};
int main(void)
{
struct student data;
data.age=18;
strcpy(data.name,"abcd");
printf("名前は%sで、年齢は%d",data.name,data.age);
func(data);
return 0;
}
void func(struct student a)
{
a.age=20;
strcpy(a.name,"efgh");
printf("名前は%sで、年齢は%d",a.name,a.age);
}
[code]
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月22日(土) 00:30
by softya(ソフト屋)
もどっても変化していないのと、ポインタ値も確認してみてください。
構造体の場合は、式には出来ないので計算は出来ませんけど。
あとは私が返答できるのは後日ですかね。
ポインタ値の場合も自分で確認してみてください。
例えば、
int *b = &a;
で
printf( "ポインタ値:%p ポインタのポインタ値:%p", b,&b );
などです。
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月22日(土) 00:50
by こにし
コード:
#include<stdio.h>
void func(struct student a);
struct student
{
int age;
int year;
};
int main(void)
{
struct student data;
data.age=18;
data.year=2012;
printf("年は%dで、年齢は%d\n",data.year,data.age);
int *b;
int *c;
c=&(data.year);
b=&(data.age);
printf( "年齢のポインタ値:%p ポインタのポインタ値:%p\n", b,&b );
printf( "年のポインタ値:%p ポインタのポインタ値:%p\n", c,&c );
func(data);
return 0;
}
void func(struct student a)
{
a.age=20;
a.year=2013;;
printf("年はは%dで、年齢は%d\n",a.year,a.age);
int *b;
int *c;
c=&(a.year);
b=&(a.age);
printf( "年齢のポインタ値:%p ポインタのポインタ値:%p\n", b,&b );
printf( "年のポインタ値:%p ポインタのポインタ値:%p\n", c,&c );
}
ポインタ値、ポインタのポインタ値を求めてみました。
すみません、これがどういう結果になるのがいいのかわかりません。
これでいいのでしょうか?
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月22日(土) 10:59
by Hiragi(GKUTH)
>すみません、これがどういう結果になるのがいいのかわかりません。
http://ideone.com/HBckLT
こうなりました、それと関数funcのプロトタイプ宣言が構造体studentより前に宣言されてしまっているので
コンパイラによっては動かないモノも・・・ 構造体を使う関数の場合プロトタイプ宣言を行うなら構造体を
先に宣言したほうがいいかと、
Re: 配列、構造体、ポインタの問題です。
Posted: 2013年6月22日(土) 11:32
by softya(ソフト屋)
メンバではなく、構造体のポインタ値を見てもらたかったんです・・・。
例で上げたのはint型のパターンで、構造体は構造体で構造体ポインタを使って欲しかったんですよ。
int型のポインタと構造体型のポインタの違いも確認して欲しい所です。 → ポインタ変数としては、ポインタ値が格納されている変数であり、sizeof()で調べてもサイズには違いはありません。ただ、int型と構造体型ではポインタとして使用した時の動作が違います。
とにかく、自分で考えて色々ためしてみてください。ここで自分で考えて色々試さないと理解できないんです。
あと何度も書いてますが、構造体代入。ためしてくださいね。
これは、関数の引数の渡し方が別変数への代入と同じであると言うことを理解してもらうのに必要なことです。