【掲示板ご利用上の注意】

 ※題名は具体的に!
 ※学校の課題の丸投げ禁止!
 ※ソースの添付は「HTML変換ツール」で字下げ!
 ※返信の引用は最小限に!
 ※環境(OSとコンパイラ)や症状は具体的に詳しく!
 ※返信付き投稿の削除は禁止!
 ※マルチポスト(多重投稿)は慎んで!

 詳しくはこちら


本当はこんなに大きく書きたくはないのですが、なかなか守っていただけなくて…。
 守ってくださいね。お願いします。(by管理人)

C言語ソース⇒HTML形式ツール掲示板2こちら


管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧

No.22426

配列や構造体の関数への値の渡し方
投稿者---AKUMA(2005/08/04 21:38:10)


AKUMAです。
関数へ値を渡す方法というのが、複数あって混乱しています。
調べてみるとなにやら、値渡しと参照渡しの二つがあるみたい
ですね。たぶんそれらが基本となっていろいろな方法があるの
かもしれません。

とくに配列と構造体の場合たくさんの関数への渡し方があり
混乱しています。

暗記すればよいのですが、理解しないまま覚えるというのは
気持ちの悪いものですし、応用もききません。しかも、すぐ
忘れてしまします。

そこで、配列と構造体への関数への値の渡し方をご指導いただ
きたいと思います。

まず、下記のが基本的な関数への値の渡し方です。
これは理解できます。
#include <stdio.h>

int sum(int);   /* プロトタイプ宣言 */

int main(void)
{
    sum(50);    /* 50を渡している */
    return 0;
}

int sum(int max)
{
    printf("%d\n",(1 + max) * max / 2);
    return 0;
}

参考にポインタ渡しの場合
int x[3];
func(x);

void func(int *px)
{
}

次に関数に配列を渡す場合です。
プロトタイプ宣言
int showarray(int *);
または
int showarray(int x[3]);

関数
int showarray(int x[]);
または
int showarray(int x[]);
int showarray(int x[3]);
int showarray(int *x); ← この場合はポインタですが、xを渡すからですね

次の場合・・・

char *name[] = {
    "徳川家康"
    "田中正造"
    "Thomas"
    "エジソン"
}

showname(name);

int showname(char **p)
{
}

プロトタイプ宣言と関数
int showname(char *p[]) ← これはポインタ配列かな?
int showname(char **p) ← これはポインタのポインタですね

多次元配列の場合・・・

int a[][2] = {
    1,2,
    3,4,
    5,6,
    7,8,
};

showint(a);

int showint(int m[][2])
{
}

関数
int showint(int **) ← これの意味がとらえられないです。
int showint(int (*m)[2]) ← これの意味もわりません。

× *m[2] → *(m[2]) という意味になり駄目だそうですが、よくわかりません。

構造体の関数への渡し方
その1
void sub1(struct DATE_DATA data[],int i);
void sub2(struct DATE_DATA data[],int i);

sub1(data,i)
sub2(data,i)

void sub1(struct DATE_DATA data[],int i)
{
}

void sub2(struct DATE_DATA data[],int i)
{
}

その2
void sub1(struct DATE_DATA *data,int i);
void sub2(struct DATE_DATA *data,int i);

sub1(&data[i],i)
sub2(&data[i],i)

void sub1(struct DATE_DATA *data,int i)
{
}

void sub2(struct DATE_DATA *data,int i)
{
}

構造体の場合ですが、上記の二つだけしか渡し方は
ないのですかね・・・

ちょっと、話はずれますが、最後に下記のことについて。
ポインタの場合は下記のようにstrを更新できるそうです。
char *str;
str = "ABC";
str = "def";

しかし、配列だとできないみたいです、なぜ、ですかね・・・
ポインタの場合と配列の場合、ともにstrには、"ABC"の先頭の
アドレスが入ってる感じがするので平気なようにみえるの
ですがね・・・

配列は・・・
char str[] = "ABC";
str = "def";
不可

未熟者ですがご指導いただければありがたいですm(__)m



この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:配列や構造体の関数への値の渡し方 22427 まきじ 2005/08/04 21:54:33
<子記事> Re:配列や構造体の関数への値の渡し方 22428 まきじ 2005/08/04 22:03:48
<子記事> Re:配列や構造体の関数への値の渡し方 22443 YuO 2005/08/05 11:03:17


No.22427

Re:配列や構造体の関数への値の渡し方
投稿者---まきじ(2005/08/04 21:54:33)


>int showint(int **) ← これの意味がとらえられないです。

int型への、ポインタのポインタです。

>int showint(int (*m)[2]) ← これの意味もわりません。

int型の要素を 2 つもつ配列へのポインタ

>構造体の場合ですが、上記の二つだけしか渡し方は
ないのですかね・・・

普通の変数や配列と同じです。
型が構造体になっただけだと思います。

>しかし、配列だとできないみたいです、なぜ、ですかね・・・
>char str[] = "ABC";
>str = "def";

配列名 str は、ポインタ定数だからです。
定数なので、str の値を変更する事はできません。


この投稿にコメントする

削除パスワード

No.22429

Re:配列や構造体の関数への値の渡し方
投稿者---RiSK(2005/08/04 22:26:52)


>>しかし、配列だとできないみたいです、なぜ、ですかね・・・
>>char str[] = "ABC";
>>str = "def";
>
>配列名 str は、ポインタ定数だからです。
>定数なので、str の値を変更する事はできません。

嘘言っちゃいけません。
strはchar[4]型でありポインタでも定数でもありません。
str = "def"; がダメなのは,配列は変更不能な左辺値として決められているからです。
しかし,定数ではないので,要素は変更できます。

>>char str[] = "ABC";

この場合の "ABC" は初期化子です。
char str[] = {'A', 'B', 'C', '\0'};
と同じ事であり,
たまたま文字列リテラルのような形をしているだけです。


# あと,「思います」の多用は議論にふさわしくありません。


この投稿にコメントする

削除パスワード

No.22430

Re:配列や構造体の関数への値の渡し方
投稿者---まきじ(2005/08/04 22:56:30)


>str = "def"; がダメなのは,配列は変更不能な左辺値として決められているからです。

はい、その通りでした。
X3010 で確認しました。


この投稿にコメントする

削除パスワード

No.22432

Re:配列や構造体の関数への値の渡し方
投稿者---AKUMA(2005/08/05 05:14:00)


RiSK 様

お忙しい中お答えいただき、ありがとうございます。

>嘘言っちゃいけません。
>strはchar[4]型でありポインタでも定数でもありません。
>str = "def"; がダメなのは,配列は変更不能な左辺値として決められているか>らです。
>しかし,定数ではないので,要素は変更できます。

とにかく変更不能な左辺値と決められているのですね・・・
変更不能な左辺値って難しいですね・・・

他で調べたらstrは配列の名前で変数ではないと書いてありました。
よく考えるとstrは、配列の先頭をさしているのですよね?
間違えかな?






この投稿にコメントする

削除パスワード

No.22435

Re:配列や構造体の関数への値の渡し方
投稿者---RiSK(2005/08/05 09:21:03)


>>strはchar[4]型でありポインタでも定数でもありません。
>>str = "def"; がダメなのは,配列は変更不能な左辺値として決められているか>らです。
>>しかし,定数ではないので,要素は変更できます。
>
>とにかく変更不能な左辺値と決められているのですね・・・
>変更不能な左辺値って難しいですね・・・
>
>他で調べたら

どこで調べましたか,URL/本を教えてください。

>strは配列の名前で

そのように定義されていれば名前(識別子)です。
ex. char str[4];

>変数ではないと書いてありました。

「変数」という語が曖昧なので,正しいとも間違いとも言いにくいです。
オブジェクト=いわゆる変数 の場合
間違い。配列もオブジェクト。配列には(たまたま)代入できないが,
constでない限り,要素は変更できる。すでに,書いたとおり。
代入可能=いわゆる変数 の場合
(私は納得いかないけど)正しい。
>よく考えるとstrは、配列の先頭をさしているのですよね? 「配列名はポインタだ」とか,説明している本があったら捨ててください。 曖昧・不完全で,誤解するだけです。 str は配列と定義されている限り,配列です。 このスレ,一連の説明であれば, char[4]型 (char型の四つの要素をもつ配列型)です。 良いでしょうか? 配列は配列です。 しかし,配列の先頭要素へのポインタに成り下がることがあります。 誤解は「ほとんどの場合,成り下がる」事にあります。 それで,多くの人が配列はポインタだと思いこんでしまうわけです。 そこで,「成り下がる事は(多いけど)例外なのだ」と覚えることをお勧めします。 1 char str[4] = "ABC"; 2 sizeof(str); 3 &str; 1の"ABC", 2のstr, 3のstrは配列のままで,それ以外のパターンでは例外として成り下がります。



この投稿にコメントする

削除パスワード

No.22441

ありがとうございました
投稿者---AKUMA(2005/08/05 10:56:28)


RiSiK 様

お忙しい中、お答えいただき、ありがとうございます。

どこで調べましたか,URL/本を教えてください。
猫でもわかるC言語プログラミングです。

>よく考えるとstrは、配列の先頭をさしているのですよね?

「配列名はポインタだ」とか,説明している本があったら捨ててください。
曖昧・不完全で,誤解するだけです。

そうですか・・・

>しかし,配列の先頭要素へのポインタに成り下がることがあります。
>誤解は「ほとんどの場合,成り下がる」事にあります。
>それで,多くの人が配列はポインタだと思いこんでしまうわけです。

わかってきました。

ありがとうございました。




この投稿にコメントする

削除パスワード

No.22428

Re:配列や構造体の関数への値の渡し方
投稿者---まきじ(2005/08/04 22:03:48)


>× *m[2] → *(m[2]) という意味になり駄目だそうですが、よくわかりません。

添え字演算子 [] は ポインタ演算子 * より優先順位が高いから、
*m[2] と *(m[2]) は同じ意味になります。


この投稿にコメントする

削除パスワード

No.22431

Re:配列や構造体の関数への値の渡し方
投稿者---AKUMA(2005/08/05 05:06:15)


まきじ様 お答えいただきありがとうございます。

>>× *m[2] → *(m[2]) という意味になり駄目だそうですが、よくわかりませ>>ん。
>
>添え字演算子 [] は ポインタ演算子 * より優先順位が高いから、
>*m[2] と *(m[2]) は同じ意味になります。

そうですね、同じになるようですね・・・
*(m[2])←これだとどういう意味になりますか?

(*m)[2]←これだとどうですか?

ここらへんかなり混乱しますね・・・



この投稿にコメントする

削除パスワード

No.22433

Re:配列や構造体の関数への値の渡し方
投稿者---まきじ(2005/08/05 08:30:44)


>*(m[2])←これだとどういう意味になりますか?

int 型へのポインタの要素を 2 もつ配列

>(*m)[2]←これだとどうですか?

22427 のレスを見てください。


この投稿にコメントする

削除パスワード

No.22442

ありがとうございました
投稿者---AKUMA(2005/08/05 10:57:42)


まきじ様

お忙しい中、お答えいただきありがとうございました。


この投稿にコメントする

削除パスワード

No.22444

Re:配列や構造体の関数への値の渡し方
投稿者---YuO(2005/08/05 11:03:48)


>>>× *m[2] → *(m[2]) という意味になり駄目だそうですが、よくわかりませ>>ん。
>>添え字演算子 [] は ポインタ演算子 * より優先順位が高いから、
>>*m[2] と *(m[2]) は同じ意味になります。

int (*m)[2];


int *m[2]

とあった場合,*や[]は演算子ではなく宣言子と呼びます。
また,優先順位は演算子とは別に定義されています。


>*(m[2])←これだとどういう意味になりますか?

int *(m[2]);
とあった場合,識別子がmで,括弧の中に[2]だけですから,
mは「(何らかの型)を要素型とする2個の要素からなる配列」型となります。
次に,括弧の外側はint *ですから,宣言子*を処理して,
mは「『(何らかの型)へのポインタ』型を要素型とする2個の要素からなる配列」型となります。
最後に,のこっているのがintなので,(何らかの型)はintになり,
mは「『intへのポインタ』型を要素型とする2個の要素からなる配列」型となります。


>(*m)[2]←これだとどうですか?

同様に考えます。

int (*m)[2];
とあった場合,識別子がmで,括弧の中に*だけですから,
mは「(何らかの型)へのポインタ」型となります。
次に,括弧の外側はint [2]ですから,宣言子[2]を処理して,
mは「『(何らかの型)を要素型とする2個の要素からなる配列』型へのポインタ」型となります。
最後に,のこっているのがintなので,(何らかの型)はintになり,
mは「『intを要素型とする2個の要素からなる配列』型へのポインタ」型となります。


int *m[2];
とあった場合,識別子がmで,宣言子が*と[2]です。
宣言子の優先順位の関係で,[2]が先に処理され,
mは「(何らかの型)を要素型とする2個の要素からなる配列」型となり,
次に,宣言子*が処理され,
mは「『(何らかの型)へのポインタ』型を要素型とする2個の要素からなる配列」型となります。
最後に,のこっているのがintなので,(何らかの型)はintになり,
mは「『intへのポインタ』型を要素型とする2個の要素からなる配列」型となります。



この投稿にコメントする

削除パスワード

No.22479

Re:配列や構造体の関数への値の渡し方 【Eratta Only】
投稿者---YuO(2005/08/06 00:45:52)


int (*m)[2];


int *m[2]


int (*m)[2];


int *m[2];


;が抜けていました。
# 宣言として独立させておきたかったので。


この投稿にコメントする

削除パスワード

No.22443

Re:配列や構造体の関数への値の渡し方
投稿者---YuO(2005/08/05 11:03:17)


> とくに配列と構造体の場合たくさんの関数への渡し方があり
> 混乱しています。

基本的には,
・型Tのオブジェクトを受け取りたい場合,T型の引数を宣言する
・型Tのオブジェクトを変更したい場合,T *型の引数を宣言する
です。配列だろうが構造体だろうが,この原則は崩れません。

ただし,構造体に関しては,サイズが大きい時に,
・型Tのオブジェクトを受け取りたい場合,const T *型の引数を宣言する
ということがあります。


> 多次元配列の場合・・・
(snip)
> 関数
> int showint(int **) ← これの意味がとらえられないです。
> int showint(int (*m)[2]) ← これの意味もわりません。

ひとつめはダメです。
int [4][2]型をint **型に変換できません。

上記の基本に立ち戻って,int [4][2]型を受け取りたいのですから,
int showint(int m[4][2])

となります。ここで,引数における配列は,その要素型へのポインタとして扱う,という例外があるので,
int m[4][2]はint (*m)[2]とも書けます。



> しかし、配列だとできないみたいです、なぜ、ですかね・・・
> ポインタの場合と配列の場合、ともにstrには、"ABC"の先頭の
> アドレスが入ってる感じがするので平気なようにみえるの
> ですがね・・・

RiSKさんが既に述べられていますが,
配列は配列であってポインタではないからです。
# さらに,配列は代入可能ではない。



この投稿にコメントする

削除パスワード

No.22483

ありがとうございました
投稿者---AKUMA(2005/08/06 18:01:05)


YuO 様

お忙しい中、詳細な解説ありがとうございます。

もやもやしていたものが、はっきりとわかった
かんじです。

ありがとうございました


この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧