C言語のプログラミングコードの書き方でわからないところがあります><

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ほいしょー

C言語のプログラミングコードの書き方でわからないところがあります><

#1

投稿記事 by ほいしょー » 5年前

C言語のプログラミング
以下の関数を呼び出すmain関数を記述しろという問題です。試行錯誤しましたがコンパイルすら通りません。
main文で②の関数から返ってくる値を受け取る変数ってvoid (**x)();は違いますか?
②の行は何がなんだかわかりません。
どなたか取り敢えず②の行が何をしているか教えてください。。。><


void hoge(void) {
 printf("hoge\n");
}

void (*a(void))(void){ //①
 printf("a\n");
 return hoge;
}

void (*(*b(void))(void))(void){ //②
 printf("b\n");
 return a;
}

void (*(*(*c(void))(void))(void))(void){ //③
 printf ("c\n");
 return b;
}

Mana

Re: C言語のプログラミングコードの書き方でわからないところがあります><

#2

投稿記事 by Mana » 5年前

コード:

int main(void)
{
	a();
	b();
	c();
	return 0;
}
呼び出すだけならこれでおしまいだがそうじゃないっぽい?
ほいしょー さんが書きました:②の行は何がなんだかわかりません。
どなたか取り敢えず②の行が何をしているか教えてください。。。><
まずはヒント。
bが関数名。
bの直後にある()の中が引数を表す列。
それ以外のすべてが戻り値の型。

かずま

Re: C言語のプログラミングコードの書き方でわからないところがあります><

#3

投稿記事 by かずま » 5年前

ほいしょー さんが書きました: ②の行は何がなんだかわかりません。
どなたか取り敢えず②の行が何をしているか教えてください。。。><
なぜ、(1) について質問しないのですか?
次のプログラムの意味は分かっているのですか?

コード:

int main(void)
{
    a()();
    return 0;
}

ほいしょー

Re: C言語のプログラミングコードの書き方でわからないところがあります><

#4

投稿記事 by ほいしょー » 5年前

Manaさん返信ありがとうございます!
ということは、例えば①を

コード:

typedef void (*A)(void);
A  a(void);
のように置き換えたら,②は,

コード:

typedef void (*B1)(void);
typedef B1* (**B2)(void);
B2  b(void);
のようになるということですかね?分かりにくくてすいません。。。



>呼び出すだけならこれでおしまいだがそうじゃないっぽい?

多分、関数それぞれ(a,b,c)に戻り値を入れる変数がいるのかなと思います。
最初は、以下のようにやってみたのですが駄目でした。

コード:

int main(){
  void (*x)();
  void (**y)();
  void (***z)();
  x=a();
  y=b();
  z=c();
  return 0;
}

ほいしょー

Re: C言語のプログラミングコードの書き方でわからないところがあります><

#5

投稿記事 by ほいしょー » 5年前

かずまさん返信ありがとうございます!

void1 (*a(void2))(void3){  //①

①に関しては、上のようにvoidに番号を付けると、
引数がvoid2で、戻り値が "引数がvoid3で、戻り値がvoid1の関数" へのポインタである関数aの宣言と定義。と認識しています。
分かりにくくてすいません。。。

>次のプログラムの意味は分かっているのですか?
すいませんよくわかりません。。。
関数aの引数と、関数aの戻り値のポインタ先の関数の引数にそれぞれvoidを渡している?

るるら

Re: C言語のプログラミングコードの書き方でわからないところがあります><

#6

投稿記事 by るるら » 5年前

おそらくvoidの意味を知らないのではないのでしょうか?
どこから分からないのでしょうか?

ほいしょー

Re: C言語のプログラミングコードの書き方でわからないところがあります><

#7

投稿記事 by ほいしょー » 5年前

>るるらさん
いやvoidの意味は分かります。。。
コード内②の行で何をしているかいまいちわからないです。

かずま

Re: C言語のプログラミングコードの書き方でわからないところがあります><

#8

投稿記事 by かずま » 5年前

これは分かりますよね。

コード:

int main(void)
{
	hoge();
	return 0;
}
これはどうですか?

コード:

int main(void)
{
	void (*p)(void);
	p = hoge;
	p();
	return 0;
}
その次が (1) の a です。

コード:

int main(void)
{
	void (*x)(void);
	x = a();
	x();
	return 0;
}
a() は hoge を返しますから、x は hoge。x() は hoge()。

変数 x を使わないと、

コード:

int main(void)
{
	a()();
	return 0;
}
a()() は、a(); hoge();

その次が (2) の b です。

コード:

int main(void)
{
	void (*(*y(void))(void);
	y = b();
	y();
	return 0;
}
b() は a を返しますから、y は a。y() は a()。

変数 y を使わないと、

コード:

int main(void)
{
	b()();
	return 0;
}
b() は a を返しますから、b()() は、a()。

b()()(); は b(); a(); hoge();

かずま

Re: C言語のプログラミングコードの書き方でわからないところがあります><

#9

投稿記事 by かずま » 5年前

かずま さんが書きました:

コード:

	void (*(*y(void))(void);
訂正

コード:

	void (*(*y)(void))(void);

Mana

Re: C言語のプログラミングコードの書き方でわからないところがあります><

#10

投稿記事 by Mana » 5年前

こういうお遊びのような問題は関数プロトタイプだけ見て悩んでも意味ないですよ。
残りの部分が戻り値の型というのが分からないのですかね。
ヒントを順番に考えてみました?

b関数の戻り値の型は
void (*(*b(void))(void))(void)
から関数名とその直後にある括弧の引数並びを除いた部分ですよ。
voidじゃないですよ。
void (*(*)(void))(void)ですよ。
日本語で書くと「引数がvoidで戻り値がvoidの関数へのポインタを返す引数がvoidの関数へのポインタ」型ですよ。

日本語で説明するのも難しいので次のコードを見て理解してください。
かずま氏の関数呼び出し演算子の重ね掛けを理解するにはこちらを先に理解したほうがいいかもね。

コード:

int main(void)
{
	{ /* 戻り値の型を順に継承 */
		typedef void (*fnx_t)(void);
		typedef fnx_t (*fny_t)(void);
		typedef fny_t (*fnz_t)(void);
		fnx_t x = a();
		fny_t y = b();
		fnz_t z = c();
	}
	{ /* 関数プロトタイプから直に */
		typedef void (*fnx_t)(void);
		typedef void (*(*fny_t)(void))(void);
		typedef void (*(*(*fnz_t)(void))(void))(void);
		fnx_t x = a();
		fny_t y = b();
		fnz_t z = c();
	}
	return 0;
}

ほいしょー

Re: C言語のプログラミングコードの書き方でわからないところがあります><

#11

投稿記事 by ほいしょー » 5年前

>Manaさん
継承していくやり方を見て、関数bの宣言の意味がようやくわかりました。関数a,b,cの戻り値だけに着目するとわかりやすくなるんですね。
ありがとうございました!

>かずまさん
二重括弧がどうしてもしっくりきません。
二重括弧について自分なりの解釈なんですが間違っていたら教えてください。

コード:

int *k;
int l;
k = &l;
*k;
普通の変数のポインタに変数のアドレスを代入することでその変数として振る舞うことができる上記では" *k "は" l "として振る舞う。
これと同様にa()はhogeとして振る舞うので、a()()はhoge()と同じ意味を指す。

また、ここにきて初歩的な質問で申し訳ないのですが、関数aは戻り値がありますよね?main文ではその戻り値を入れる変数はなくて良いのですか?

box
記事: 1737
登録日時: 8年前

Re: C言語のプログラミングコードの書き方でわからないところがあります><

#12

投稿記事 by box » 5年前

ほいしょー さんが書きました: また、ここにきて初歩的な質問で申し訳ないのですが、関数aは戻り値がありますよね?main文ではその戻り値を入れる変数はなくて良いのですか?
誤:main文
正:main関数

普通は、関数からの戻り値は呼び出し元で使うためにあります。だって、使わないんだったらvoidでいいじゃん、って話です。
ただ、例外的に、わざと捨てていることがあります。今回のケースがこれに相当しているのかもしれません。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

かずま

Re: C言語のプログラミングコードの書き方でわからないところがあります><

#13

投稿記事 by かずま » 5年前

ほいしょー さんが書きました: また、ここにきて初歩的な質問で申し訳ないのですが、関数aは戻り値がありますよね?main文ではその戻り値を入れる変数はなくて良いのですか?

コード:

#include <stdio.h>
 
int a(void) { return 3; }

int main(void)
{
    printf("%d\n", a());
    return 0;
}
関数 a は戻り値がありますよね。
main関数では、次のプログラムのように
その戻り値を入れる変数 x はなくてよいのですか?

コード:

#include <stdio.h>
 
int a(void) { return 3; }

int main(void)
{
    int x;
    x = a();
    printf("%d\n", x);
    return 0;
}
という質問と同じですが、ご理解いただけますか?

Mana

Re: C言語のプログラミングコードの書き方でわからないところがあります><

#14

投稿記事 by Mana » 5年前

関数へのポインタの理解が十分ではないのかな?
No.4でなんとなく関数へのポインタ型変数の宣言しているようだけども。

関数名に関数呼び出し演算子を付けて関数を呼び出せるように、関数へのポインタに関数呼び出し演算子を付けて関数を呼び出すこともできる。
かずま氏のコードに続けるとこうゆうこと。

コード:

#include <stdio.h>
 
int a(void) { return 3; }
 
int main(void)
{
    int (*x)(void); /* 関数へのポインタ型の変数xを宣言 */
    x = a; /* a関数へのポインタを代入 &演算子は不要で付けても付いてないと同じ */
    printf("%d\n", x()); /* 関数へのポインタで関数呼び出し *演算子は不要で付けても付いてないと同じ */
    return 0;
}
関数の戻り値が関数へのポインタだったらそこからさらに続けて呼び出すこともできるというわけ。

アバター
三郎
記事: 17
登録日時: 8年前

Re: C言語のプログラミングコードの書き方でわからないところがあります><

#15

投稿記事 by 三郎 » 5年前

外野席からのボヤキ

c言語とはこんなにも難しいものなのでしょうか??!。
もちろん私は質問に答える能力はありません。
以前に聞いたことがあります。
C言語も高級言語だと、、、それなら誰にでもソースが分かるような記述がいいような気がしますが、
これは私の偏見でしょうか???
初心者にも分かるような記述をするのがこの言語の本来の姿と思っていました。

そうかといっても、私には分かりやすく書く方法も知りませんが。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 9年前
住所: 東海地方
連絡を取る:

Re: C言語のプログラミングコードの書き方でわからないところがあります><

#16

投稿記事 by softya(ソフト屋) » 5年前

三郎 さんが書きました:外野席からのボヤキ

c言語とはこんなにも難しいものなのでしょうか??!。
もちろん私は質問に答える能力はありません。
以前に聞いたことがあります。
C言語も高級言語だと、、、それなら誰にでもソースが分かるような記述がいいような気がしますが、
これは私の偏見でしょうか???
初心者にも分かるような記述をするのがこの言語の本来の姿と思っていました。

そうかといっても、私には分かりやすく書く方法も知りませんが。
C言語はどちらかと言うと自由度が高い言語なので、読み辛いソースコードは当然のごとく書けます。
初心者だと分かりづらいソースコードになりがちです。なので、分かりやすく書けるのは熟練者と言えます。
そもそも共同作業で分かりづらいソースコードを書くのはご法度ですので、熟練するほど読みやすいソースコードを書くようになります。

言語仕様の自由度と初心者にも書きやすい綺麗なコードを書ける仕様はだいたい矛盾します。
C言語は記述性と自由度と高速性を優先して設計されていますので、「初心者にも分かるような記述をするのがこの言語の本来の姿と思っていました。」と言う意図は本来ありませんね。

読みやすさとかわかり易さを優先したのは、COBOL,BASIC,PASCALなどの言語だと思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
usao
記事: 1552
登録日時: 6年前

Re: C言語のプログラミングコードの書き方でわからないところがあります><

#17

投稿記事 by usao » 5年前

オフトピック
>外野席からのボヤキ

まぁ,「呼び出してみろ」というのが問題になっているくらいだから
わざと わからないように 書いてあるわけで,
実際に自分でコード書くときは わからなくならないように 書けばいいと思いますよ.

私もこんなコード見せられたら「は?」ってなりますし,
実際に書かなきゃならないとしたら例えば↓みたいに自分にわかるように書きますし……

コード:

void hoge(){	printf( "hoge\n" );	}

typedef void (*FP)(void);	//hoge()に対応
typedef FP (*FPa)(void);	//a()に対応
typedef FPa (*FPb)(void);	//b()に対応

FP a()
{
	printf( "a\n" );
	return hoge;
}

FPa b()
{
	printf( "b\n" );
	return a;
}

FPb c()
{
	printf( "c\n" );
	return b;
}

閉鎖

“C言語何でも質問掲示板” へ戻る