C言語 構造体ポインタを使用した関数の扱いについて教えてください。
ゲスト
ゲスト (Tanaka)
ATOMRSS
  • コード求むID: 213
  • 登録日時:  2008/01/13 14:58
  • 最終更新日時: 2008/01/17 19:09
  • アクセス数: 2987
  • タグ:  c言語
  • codeなにがしブックマークに追加する 0 users
  • このページを del.icio.us に追加
  • このページをはてなブックマークに追加

問題文:氏名と点数を入力する処理をn 回繰り返す関数を作成し、 
Main関数でそれを呼び出し&表示するプログラムを作成せよ。 

環境 
OS:Vista 
コンパイラー:Bcc32 
使用言語:C言語

#include <stdio.h> 

struct _TEST{ 
char name[100]; 
int score; 
}; 
struct _TEST element[6]; 
struct _TEST *a[6]; 

void input_score( struct _TEST *a, int ); 

int main (void){ 
int 6; 
int 1; 

input_score(element,n); 

for(i=0;i<n;i++){ 
printf("name:%s score:%d \n",element[i].name,element[i].score); 

return 0; 


void input_score( struct _TEST *a, int ){ 
int i; 

for(i=0;i<n;i++){ 
printf("name:"); 
scanf("%s",(a[i]->name)); 
printf("score:"); 
scanf("%d",&(a[i]->score)); 



なにがまずいのか指摘していただけると助かります。

よろしくお願いします。

コメント

  • ゲスト
  • 1:ゲスト (暇人)
  • 2008/01/13 18:25

#include <stdio.h> 

#define DATA_SIZE 6

struct _TEST{ 
    char name[100]; 
    int score; 
}; 
struct _TEST element[DATA_SIZE]; 
/* struct _TEST *a[DATA_SIZE]; */

void input_score( struct _TEST *a, int ); 

int main (void){ 
    int DATA_SIZE; 
    int 0; 
    
    input_score(element,n); 
    
    for(i=0;i<n;i++){ 
        printf("name:%s score:%d \n", element[i].name, element[i].score); 
    
    return 0; 

void input_score( struct _TEST *a, int ){ 
    int i; 
    
    for(i=0;i<n;i++){ 
        printf("name:"); 
        scanf("%s", a[i].name); 
        printf("score:"); 
        scanf("%d", &(a[i].score)); 
    


GJ

  • ゲスト
  • 2:ゲスト (Tanaka)
  • 2008/01/14 03:31

ありがとうございます。

なるほど。
input_score関数内で、構造体_TEST a に代入するときは
何故、a[i].name でよいのでしょうか?

a[i]->name のようなアドレス演算子を使うべきところではないのでしょうか?


  • GoodJob
  • 0

  • ゲスト
  • 3:ゲスト (暇人)
  • 2008/01/14 14:48

例えば、
 int a[10];/* のような配列があって */
 int *p   ;/* のようなポインタがある時 */
    ;/* ポインタでアクセスすると決めた、p は、配列の先頭の要素のアドレス */
// 
 p[i]     ;/* ポインタでの配列要素へのアクセスをする */
//この時、p[i] は、ポインタ(アドレス)ですか、配列の1要素ですか?
質問文での主張はアドレスであるということであり、
コメントの主張は配列の1つの要素であるということです。

  • GoodJob
  • 0

  • ゲスト
  • 4:ゲスト (Tanaka)
  • 2008/01/15 02:32

回答ありがとうございます。

私は以下のように理解しました。
1.p &a[0]; ということと、 a; というのは同じことを表しているということ。
2.a[3]:配列aの3という要素そのものを指す。
p[3]:配列aの3のアドレスを指し示すもの。(つまり→ *p[3]=a[3])

そして、構造体において同様に理解すると、
(投稿されたソース)a element となっていると考えられる、また、aはポインタの演算であることを考えると…
a[i]->nameと使用するのが正しいと考えられるのですが、この思考はどこがおかしいのでしょうか? 

  • GoodJob
  • 0

  • ゲスト
  • 5:ゲスト (暇人)
  • 2008/01/15 07:44

>2.a[3]:配列aの3という要素そのものを指す。 
>p[3]:配列aの3のアドレスを指し示すもの。(つまり→ *p[3]=a[3]) 
それ(a[3]とp[3])を区別するのが(というか動作の理解が)間違っていますね。
配列演算子は、
アドレス[その型の要素の位置]でその型の要素を取り出すものです。
その意味で、
a[3]とp[3]は同じモノです。
言い換えれば
p[3]は、*(p+3)と等価な演算をします。
a[3]=p[3]=*(p+3)=*(a+3)
です

  • GoodJob
  • 0

  • ゲスト
  • 6:ゲスト (Tanaka)
  • 2008/01/15 12:26

回答ありがとうございます。

私は以下のように理解しました。
1.配列である ⇒ アドレスであるということ。
であるならば、a と *p は本質的に何も変わらないということ。

2.元のソースに戻って、a[i]->name のような表記が間違っていることを理解しました。
何故ならば、a[i]->name 自体が考え方として間違っているからであると理解しました。
例えば、printf("%d",*p[i]); → 無効な間接参照とでます。

ありがとうございました。疑問が解決致しました。

しかし…配列そのものがポインタだと理解するならば、配列にポインタを定義する(p a)ような動作は不要と考えられるのですが、配列を使用する場合はポインタは不要なのでしょうか?

  • GoodJob
  • 0

  • ゲスト
  • 7:ゲスト
  • 2008/01/15 15:09

>配列そのものがポインタだと理解するならば
配列 a[n] がある時
は、配列としての情報を持つと共に、先頭のアドレス定数と考えることができます。
[] は、アドレス演算を行いますが、
「配列そのもの」がポインタというのは語弊があります。

>配列を使用する場合はポインタは不要なのでしょうか?
質問の意図するところがわかりませんが、

例えば、
input_score(&element[3],3);
で呼び出すこともできますし、
for の終了処理部分でa++
つまり
for(i=0;i<n;i++,a++){ 
なんてすれば、
scanf("%s",a->name);
とできて、
この場合、配列アクセスのためのアドレス演算がちょっと省略(構造体メンバ毎に同じ計算をしなくてもよい)できます。
 


  • GoodJob
  • 0

  • ゲスト
  • 8:ゲスト (Tanaka)
  • 2008/01/15 16:35

回答ありがとうございます。
勉強になります。

私は以下のように理解しました。

 配列はあくまで、配列の先頭要素のアドレスを指すもので配列そのものではないということ。
int であり、a[1]とa[2]があるとするならば、
a[1]のアドレス…0000000A
a[2]のアドレス…00000014 
のようになってるとすると。
a[1]は0000000Aという番地そのものを指すポインタであるといえる。
a[2]も00000014という番地のポインタであるといえる。

<話題その1>

質問の意図が伝わらなくて申し訳ありません。

配列がポインタであるならば、
int a[10]; int *p;とすると、p=a;といったような使用方法にメリットはないのではないか、ということです。


<話題その2>

ちなみに、scanf("%s",a->name);に変更して実行したところ、i=n(つまりi=6)の結果しか代入されないようなのですが。


<話題その3>

また、教えていただいたように、a[1]=p[1]=*(a+1)=*(p+1)だと理解すると、
問題文に沿ったプログラム内において、
scanf("%s",( *(a+1).name) );
という記述は間違ってはいないと考えます。
考え方に間違いが生じているのでしょうか?

  • GoodJob
  • 0

  • ゲスト
  • 9:ゲスト (暇人)
  • 2008/01/15 17:56

>配列はあくまで、配列の先頭要素のアドレスを指すもので配列そのものではないということ。 
例えば、
int data[10];
int *p;
の時
sizeof(data)
sizeof(p)
は、どのような結果になると思いますか?

>a[1]は0000000Aという番地そのものを指すポインタであるといえる。
その番地から要素を取り出すという意味でポインタと言ってもいいような気がするけど、
それをいうなら
int i=5;
だって、
変数iは、i の番地のポインタだよ。

>p=a;といったような使用方法にメリットはないのではないか
ポインタを使って配列にアクセスすることにメリットはあるよ。
すでに示したつもり。

>scanf("%s",a->name);に変更して実行したところ、i=n(つまりi=6)の結果しか代入されないようなのですが。 
前後(他)の部分で間違いがあると思う。

>scanf("%s",( *(a+1).name) ); 
>という記述は間違ってはいないと考えます。 
scanf("%s",( a[i].name) );

scanf("%s",( *(a+i).name) );
が同じという意味で
"yes"

  • GoodJob
  • 0

  • ゲスト
  • 10:ゲスト
  • 2008/01/17 19:09

以下の説明はけっこう乱暴です。
しかし的は外してないと思います。

int a[10];
int* p;
と宣言されているとして説明します。

1.
・論理的な問題、C言語の決まりごとの問題
・文法上の問題、書き方の問題
この2つを分けて考えましょう。

2.
論理的な問題です。
ポインタと配列は全く違います。
というか同じレベルで語るものではないです。
ポインタは変数です。
変数には値型変数とポインタ型変数があるのです。
(値型変数というのは int a; とかいわゆる普通の変数です)
で、配列というのは複数の変数が連続したものですね。

3.
論理的な問題です。
アドレスは「何の」アドレスなのかが重要です。
ポインタに関しては2種類のアドレスがあります。
 ・ポインタ自体のアドレス
 ・ポインタが指すアドレス
どうもこの2つを混同しているように思えます。
代入で変更できるのは「ポインタが指すアドレス」だけです。

4.
論理的な問題です。
.演算子や->演算子は変数に対してしか使用できません。
.演算子は値型変数に対して使い、->演算子はポインタ型変数に対して使います。
a->name は文法的には合ってるのでコンパイル可能ですが、
論理的にはやや破綻しています。
それは a->name がコンパイラによって(&a[0])->name と解釈されるからです。

5.
文法的な問題です。
各式が表す「値」の型を考えてみましょう。
&a[0]...ポインタ型変数(int*型)
a[0]...値型変数(int型)
p...ポインタ型変数(int*型)
*p...値型変数(int型)
&p...ポインタ型変数(int**型、ポインタのポインタ)

6.
文法的な話です。
 C言語では型変換つまりキャストがあちこちで行われます。
文法的に型のおかしい変数があると勝手にキャストが行われます。
例えばlong型変数とint型変数の値を比較する際には、int型変数はlong型にキャストされます。別な型のままだと比較できないからです。
これは暗黙的に行われますが、プログラマは知っておかなければなりません。
 結論から言ってしまえば[]演算子を使うその瞬間だけは、aはポインタ型変数にキャストされており、そのキャストの際にaの先頭アドレスが代入されているのです。C言語ではそういう「配列→ポインタ型変数」のキャストが最初から規定されているのです。
 これはC言語を作った人たちが「[]演算子使う時や先頭アドレス取ってくる時に、ポインタと配列を同じように扱えたら便利だな~」と思って勝手に(?)決めた約束事です。

 要するにポインタと配列は別物なのですが、特定のケースで同じように使えるようにしてあるだけなのです。

GJ

前へ 1 次へ

コメントする

[block]から[/block]までの範囲はブロック表示されます。
部分的に目立たせたい時や、引用などにお使いください。

[code]から[/code]までの範囲は等幅表示されます。
ソースコードや設定ファイルの記述などにお使いください。

ゲスト投稿者:ゲスト:

関連ソースコード・ノウハウを登録

PDFLib | A library for processing PDF on the fly プレゼン公開・共有サイト handsOut.jp オープンタイプ株式会社 チーム・マイナス6% - みんなで止めよう温暖化

ブックマークコメント