mainの外に変数 vs ポインタ渡し

このQ&Aのポイント
  • C++についての質問です。関数の外側でも変数を宣言できることを知りましたが、何か問題があるのでしょうか?
  • ポインタ渡しで書く場合と、mainの外に変数を宣言する場合で、どのような問題や危険性があるのでしょうか?
  • 関数の外側で変数を宣言することは便利ですが、適切に使用する必要があります。
回答を見る
  • ベストアンサー

mainの外に変数 vs ポインタ渡し

C++についての質問です。プログラミング初心者ですが、よろしくお願いします。 最近、関数の外側でも変数を宣言できることを知りました。関数の外側で変数を宣言すると、全ての関数でその変数にアクセスすることができ大変便利なように思います。 「わざわざポインタ渡しなどする必要はないのでは?」と思ってしまいました。 これは何か問題があるのでしょうか? 初心者の言葉で説明しても理解しにくいかと思いますので、例として「足し算するプログラム」を以下に記載します。 ポインタ渡しで書くと、以下のような感じになるかと思います。 //●ポインタ渡し #include "stdafx.h" #include <iostream> void func(int x,int y,int *pans){ *pans = x+y; } void main(){ int a=10, b=20, ans; func(a,b,&ans); std::cout << ans << std::endl; } しかし、mainの外に変数を宣言すれば //●mainの外に変数 #include "stdafx.h" #include <iostream> int a,b,ans; void func(int x,int y){ ans = x+y; } void main(){ a=10; b=20; func(a,b); std::cout << ans << std::endl; } ansをポインタ渡しする必要なく、funcの計算結果をansに代入できました。 「●mainの外に変数」のプログラムはどのような問題や危険性を孕んでいるのでしょうか? 以上になります。長文お読みいただきありがとうございました。 よろしくお願いいたします。

質問者が選んだベストアンサー

  • ベストアンサー
  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.2

例えば、 機能を追加して int func0(int x,int y,int z){ ans = x - y ; return ans -z; } を作ります。 void main(){ a=10; b=20; func(a,b); std::cout << ans << std::endl; int c=func0(30,40,50) ; std::cout << c << std::endl; std::cout << ans+c << std::endl; } とすると、 std::cout << ans << std::endl; → 30 std::cout << c << std::endl; → -60 と出力されます。 ということは std::cout << ans+c << std::endl; で期待するのは、 ans 30 + c -60 = -30 となりますが、実際には「-70」が出力されます。 これは、func0で途中計算に ans = x - y ; としてしまったため、ansが変わってしまったからです。 この程度の規模なら、管理もできるでしょう。 ですが、例えば、 「std::cout は実はグローバル変数ansを書き換える」なんてことになっていたらどうでしょうか? 標準ライブラリでは、そのようなことが無いように作られていますが、自作プログラムだと、ついうっかりやってしまう可能性があります。 実用的なプログラムとなると、数千~数十万といった行数になってきます。その中から、グローバル変数がどこで使われているか調べるのは並大抵のことではありません。 変数の有効範囲はなるべく狭く。必要なところだけで有効なようにする。 というのが、現在の主流の考えです。

Mods-Rockers
質問者

お礼

詳細かつ例題まで載せてくださり、ありがとうございます。 これは「グローバル変数」と言うのですね。確かに期待される結果と違うものが出力されました。そして、この程度の行数でも変数がどこでどう変化したか追うのに苦労してしまいました。 『変数の有効範囲はなるべく狭く。必要なところだけで有効なようにする。』 これは肝に銘ずることにします。 ご回答ありがとうございました。ベストアンサーとさせていただきます。

その他の回答 (1)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

「全ての関数でその変数にアクセスすることができ」るのが, まさに利点であると同時に問題点です. 「いつの間にか値を変えることができる」ってことだから. ところで, 外部変数とした後者のプログラムで, なぜ func に a や b を引数として渡しているのですか?

Mods-Rockers
質問者

お礼

簡潔かつお早いご回答下さりありがとうございます。 大きな規模のプログラムになると問題が起こってくるのでしょうね。今後このような書き方をしないよう注意しようと思います。ありがとうございました。 ちなみに、質問に記載したプログラムは、この質問のために書いたもので特に意味のあるものではありません。初心者の思いつきゆえ、理解しがたいところがあったかと思いますがご容赦ください…

関連するQ&A

  • 参照渡し と ポインタ渡し

    参照渡し と ポインタ渡し はどういう時に使い分けるんですか? VOID型の自作関数内でメインのブール値を書き替えたいんだけど #include <iostream.h> void ref( int &b ) { b = false; } void ptr( int *b ){ ( *b ) = true; } main(){  bool b = true;  ref( b );  cout << b;  ptr( &b );  cout << b; } だとコンパイルエラーでした。 うまくいくソースを教えてください。

  • グローバル変数について

    ◎1--------------------------------- #include<stdio.h> void func(void); int glb; int main(void) { int a=20; glb=30; printf("main a=%d glb=%d\n",a,glb); func(); return 0; } void func(void) { int b=88; printf("func b=%d glb=%d\n",b,glb); } ------------------------------------- ◎1の実行結果----------------------- main a=20 glb=30 func b=88 glb=30 ------------------------------------- ◎2--------------------------------- #include<stdio.h> void func(void); int glb; int main(void) { int a=20; func(); printf("main a=%d glb=%d\n",a,glb); return 0; } void func(void) { int b=88; int glb=30; printf("func b=%d glb=%d\n",b,glb); } ------------------------------------- ◎2の実行結果----------------------- func b=88 glb=30 main a=20 glb=0 ------------------------------------- 以上2つのプログラムで、◎1は参考書を参考に作成したものです。 ◎1のプログラムで、グローバル変数glbの値をmain( )関数内で設定していたので、次に◎2のようにfunc( )という関数プロトタイプ内で、グローバル変数glbの値を設定し、main( )関数内のprintf文でも表示させようと思ったら、「glb=0」となってしまいました。 なぜこのようになってしまうか、教えてもらえたら嬉しいです。

  • gcc: incompatible pointer type

    以下のCソースでコンパイルすると、warning: passing arg 1 of `func_b' from incompatible pointer type となります。 void (*p_func)() は、引数を省略しているので int として扱われるということでしょうか? #include <stdio.h> #include <stdlib.h> void func_a( unsigned char x ){ printf( "x=%d\n", x ) ; } void func_b( void (*p_func)() ){ p_func( 1 ) ; } int main(){ func_b( func_a ) ; return 0 ; }

  • 【C++】関数ポインタの代入

    C++の関数ポインタについて質問です。 下記のように関数ポインタを宣言し、3通りの代入を行ってみました。 (3)のように関数名の頭に&を付けた場合と(2)のように&を付けなかった場合で 全く動きが同じになってしまうのですが、何故なのでしょうか? ------------------------------------------ #include "stdafx.h" #include <iostream> using namespace std; void Func1(){ cout<<"Func1が呼ばれました。"<<endl; return; } int main() { //(1) void (*fp1_1)(); fp1_1 = Func1; fp1_1(); //(2) void (*fp1_2)()=Func1; fp1_2(); //(3) void (*fp1_3)()=&Func1; fp1_3(); getchar(); return 0; }

  • C言語のポインタの考え方について

    ポインタについて理解ができていないのでお聞きしたいのですが 値を交換する関数のプログラミングでこの場合ポインタ で以下にしないといけないと思います。 #include<stdio.h> void swap(int *a int *b){ int c; c=*a; *a=*b; *b=c; } main(){ int x,y; x=123; y=456; swap(&x,&y); printf("x = %d, y = %d\n", x, y); } またポインタを使用せず以下のプログラムではなぜダメのでしょうか。 よろしくお願い致します。 #include<stdio.h> void swap(int a int b){ int c; c=a; a=b; b=c; } main(){ int x,y; x=123; y=456; swap(x,y); printf("x = %d, y = %d\n", x, y); }

  • 誤った関数に関する値渡しについて

    こんにちは、まずはソースを記述します。 #include<iostream> using namespace std; //誤ったswap関数の宣言 void swap(int x, int y); int main() { int num1 = 5; int num2 = 10; cout << "変数num1の値は" << num1 << "です。\n"; cout << "変数num2の値は" << num2 << "です。\n"; cout << "変数num1とnum2の値を交換します。\n"; swap(num1, num2); cout << "変数num1の値は" << num1 << "です。\n"; cout << "変数num2の値は" << num2 << "です。\n"; return 0; } //誤ったswap関数の定義 void swap(int x, int y) { int tmp; tmp = x; x = y; y = tmp; } >>関数内で仮引数xとyの値を交換する処理を行っていても、これは変数num1とnum2の値を「コピー」した5と10を交換しているにすぎません。 swap関数内で値を交換しても、呼び出し元の変数であるnum1とnum2に影響を与えることができません。 ・・の文章の中から質問ですが値渡しとはどういうことでしょうか? 参照渡しとはどう違うのでしょうか? ご教示お願いします。

  • C言語の基本的な質問ですが、関数へのポインタの宣言

    関数へのポインタの質問です。 下のように、関数へのポインタを使ったプログラムを書きました。 (関数へのポインタを理解するためのものなので、実用的な意味はありません。(*^_^*) また、このプログラムはコンパイルもリンクも実行も問題なく出来ます。) #include <stdio.h> int add_func(int,int); (*func_p0) (int,int); int main(void) { int (*func_p1) (int,int); int (*func_p2) ( ); int hoge0,hoge1,hoge2; func_p0=add_func; hoge0=func_p0(3,5); printf("0 : 3+5は%d\n",hoge0); func_p1=add_func; hoge1=func_p1(3,5); printf("1 : 3+5は%d\n",hoge1); func_p2=add_func; hoge2=func_p2(3,5); printf("2 : 3+5は%d\n",hoge2); return(0); } int add_func(int x, int y) { return(x+y); } func_p0のように戻り値の型を書かない場合と、func_p1やfunc_p2のように戻り値の型を書くのとでは何が違うのでしょうか。 func_p0は外部変数ですが、自動変数にする(main関数の中で同様に宣言。)とコンパイルエラーになります。 それはなぜですか。 func_p1のように引数の型が書いてあるのと、func_p2のように引数の型が書いていないのでは何が違うのでしょうか。 int (*func_p2) ( );というのは、int (*func_p2) (void);とは違うんですよね?

  • C++ 関数プロトタイプと値渡し・参照渡しについて

    次のコードは、入門書にあった値渡しのサンプルです。 値渡しなので、a=5 ,b=10が出力されます。 void swap(int x,int y); //←抜けていた int main(){ int a=5; int b=10; swap(a,b); cout<<"a="<< a << "\n"; cout<<"b="<<b<<"\n"; } void swap(int x,int y){ int tmp=x; x=y; y=tmp; } しかし、自分で入力したところ何故かa=10,b=5が出力されました。 (VisualC++2008で実行しました。) よく見てみると、上記1行目の関数プロトタイプが抜けていました。 入門書を読んだ限りでは、次の2点が理解できません。 (1)main関数の後ろにswap関数があり、関数プロトタイプが無いのでコンパイルエラーになるはずなのにならない (2)値渡しのはずなのに参照渡しと同じ結果になる よろしくお願いします。

  • ポインタを使った構造体のプログラム

    ポインタを使ってメンバに値を入力して表示するプログラムを作ったのですが、mainのstruct XYZ aというオブジェクトと*bというそれを指すポインタを使ってプログラムを表示するにはどうすればいいのでしょうか。 これがプログラムです。 #include <stdio.h> struct XYZ { int x; long int y; double z; }; void set_xyz(struct XYZ *p,int x,long int y,double z) { p->x=x; p->y=y; p->z=z; } //void set_xyz(struct XYZ *,int,long int,double); int main() { struct XYZ a = {12,999999,1.41421356},*b; //ここのポインタ変数bでエラーが表示されます。 set_xyz(b,a.x,a.y,a.z); printf("a.x = %d\na.y = %d\na.z = %lf\n",b->x,b->y,b->z); return 0; } エラーの内容は「初期化されていないローカル変数 'b' が使用されます」となっています。 初歩的な質問ですみません・・・。

  • 配列とポインタについて

    #include <stdio.h> int main() { char x[3]; char *y; x[0]='a'; x[1]='b'; x[2]='\0'; y="abc"; printf("xの値は%s\n",x); printf("yの値は%s\n",y); } 通常の配列宣言では、このままだと文字列をまとめて 代入できないのに対して、ポインタ変数ならまとめて代入することができるのは何故ですか?そういう仕組みだと言われてしまえば、それまでなんですが・・・

専門家に質問してみよう