• ベストアンサー

配列の不正アクセスについて

C++初心者です。 配列の不正アクセスの例外処理について教えてください。 void func(int* a){   try{     a[5]=1;   }catch(...){     printf("error!");   } } void main(){   int a[5];   func(a); } 上記のような配列の不正アクセスに対し、 例外を発生させたいのですが、 現状、例外は発生せず動作してしまいます。 例外を発生させ、安全に動作するようにするには どうしたらいいのでしょうか? すいませんが、お願いします。

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

  • ベストアンサー
  • jacta
  • ベストアンサー率26% (845/3158)
回答No.1

普通の配列では例外は発生しません。 arrayのatメンバ関数を使えば同様のことが実現できるはずです。 #include <array> #include <stdio.h> void func(std::array<int, 5>& a){   try{     a.at(5)=1;   }catch(...){     printf("error!");   } } int main(){   std::array<int, 5> a;   func(a); } > 安全に動作するようにするには mainの返却値をintにしないと未定義の動作になります。 また、printfを使うのであれば、<stdio.h>をインクルードする必要があります。

fcknsho
質問者

お礼

素早い回答ありがとうございます。 標準ライブラリを使うのですね! 早速、修正します。 ありがとうございます。

その他の回答 (2)

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.3

おかしな回答があるので再度回答します。 > void func(int a[5]) ↑のように書いても、aは配列型ではなくポインタ型になります。 したがって、sizeof(a)/sizeof(a[0])と書いても、要素数は取得できず、でたらめな結果しか得られません。 単純な配列で要素数も関数に渡したいのであれば、別の引数として渡すか、次のようにテンプレートを使います。 template <std::size_t N> void func(int (&a)[N]) {   /* 省略 */ } あるいは、サイズが必ず5なのであれば、 void func(int (&a)[5]) {   /* 省略 */ } としてもよいでしょう。

fcknsho
質問者

お礼

訂正ありがとうございます。 初心者のため配列の取り扱いには 悩まされているので、 こういった情報は本当にためになります。 ありがとうございました。

  • chie65535
  • ベストアンサー率43% (8524/19375)
回答No.2

言語仕様上、 func(int* a) で受けたaは「ポインタ」であり、このポインタは「int配列のどこを指しているか判らない」ので、範囲チェックは出来ません。 例えば、呼び出し元で func(&a[2]); として呼び出すと、func関数内での有効な添え字の範囲は「-2から2」になります。 いつも有効範囲が「0~4」だとは限らないのです。 なので、配列の添え字は、基本「範囲チェックもされないし、範囲外をアクセスした場合は動作が未定義」なのです。 以下のように、引数をポインタにせず、配列の要素数が明示された配列の参照渡しを行い、関数内で「要素数が何個あるのか判るように書いて」から、assertマクロで「範囲外チェックを行う」のが良いでしょう。 #include <assert.h> void func(int a[5]) { assert(5 < sizeof(a)/sizeof(a[0])); /*範囲外なら異常終了*/ assert(5 >= 0); /*範囲外なら異常終了*/ a[5] = 1; } int main(void) { int a[5]; func(a); return 0; }

fcknsho
質問者

お礼

回答ありがとうございます。 assertの場合だとプログラムが中断するため、 私の理想の動作と少し違います。 中断せず、例外として処理することで、 内部的に不正アクセスを対処したかったので… 説明不足で申し訳ありません。 しかし、記述方法はとても参考になりました。 ありがとうごうざいました。

関連するQ&A

  • 配列の受け渡し

    全く原因が分からないので質問させていただきます. 次のようなプログラムがあります. メイン関数で配列を宣言して, これを関数funcに渡して,func内で処理を行う. その後,メイン関数でprintf()を使って配列の内容を表示させる. 私の書いたソースは次のようになっています. int main(void) { double data[]={1.0, 2.0, 3.0, 4.0}; for(i=0; i<4; i++) { printf("%f\n", data[i]); } func(data, 4); for(i=0; i<4; i++) { printf("%f\n", data[i]); } } void func(double *f, int n) { 配列に処理を行う } メイン関数の中で, 一つ目のprintf()はちゃんと配列dataの初期値を表示します. ところが,二つ目のprintf()の手前で, 「例外」とエラーがでてきます. (コンパイルは通っています.) これが何故なのか,さっぱり分かりません. 関数func()の最後にprintf()を書いてみたところ, ちゃんと処理を行った後の正しい値が表示されます. なので,関数func()自体にバグはないように思うのです. 原因が分かる方,いらっしゃいましたら, どうぞよろしくお願いします.

  • C言語 動的確保とポインタ参照について

    以下のようなプログラムについて質問させて頂きます. main文で宣言されているaに配列を動的確保したいのですが,funcの関数内でaにアクセスする方法が分かりません.*(a[i])かな,とは思ったのですが上手く動作しませんでした. func実行後のmain文からはaの要素にアクセス出来るので,確保自体は成功していると思うのですが,如何でしょうか・・・? 宜しくお願いします. void func(int **a) {  *a = new int[32]; for(int cnt=0; cnt<32; cnt++) { /* aの配列の要素に値を代入したい(a[i] = i のように) */ } } int main(void) { int *a = NULL; func(&a); }

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

    ◎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」となってしまいました。 なぜこのようになってしまうか、教えてもらえたら嬉しいです。

  • callocで二次元配列を作成するには?

    今、動的オブジェクトの勉強をしております。 動的の一次元配列の作り方として #include <stdio.h> #include <stdlib.h> int main(void) {    int *a;    int x;    printf("配列の大きさX入力>");    scanf("%d",&x);    a=calloc(x,sizeof(int));    return (0); } これでいいと思うんですが動的な2次元配列を 作りたいときはどのようにすればよろしいのでしょうか? (↓作りたい二次元配列の例(1)↓) int main(void) {    int *a;    int x , y;    printf("配列の大きさX入力>");    scanf("%d",&x);         //5と入力    printf("配列の大きさY入力>");    scanf("%d",&y);         //10と入力    上のように入力するとa[5][10]という配列が完成する } よろしくお願いします

  • 引数で指定された配列の要素数の取得

    どうもこんにちは。 C言語でプログラムを作成しています。 ある関数に配列を渡すことを考えていますが、渡した配列の要素数を取得する方法は何かありますか? 標準の関数を見ても、配列の先頭アドレスのポインタとともに、配列の要素数を渡しているものばかりで、配列のポインタを渡しているものは見かけません。 要素数があらかじめわかっていれば、それを引数の型に指定できますが、呼び出されるまで不明な場合はうまくいきません。 配列の要素数も引数として一緒に渡す必要がありますか? [作ってみたサンプル] #include <stdio.h> #include <stdlib.h> #include <string.h> // func1 と func2 をまとめられないだろうか。。。 void func1(int (*p)[10]) { ________int n = sizeof(*p) / sizeof((*p)[0]); ________int i; ________for (i = 0; i < n; i++) { ________________printf("%d\n", (*p)[i]); ________} ________printf("\n"); } void func2(int (*p)[5]) { ________int n = sizeof(*p) / sizeof((*p)[0]); ________int i; ________for (i = 0; i < n; i++) { ________________printf("%d\n", (*p)[i]); ________} ________printf("\n"); } int main(int argc, char *argv[]) { ________int ary1[10] = { 2, 4, 6, 8, 0, 1, 3, 5, 7, 9 }; ________int ary2[5] = { 3, 6, 9, 12, 15 }; ________func1(&ary1); ________func2(&ary2); ________return 0; }

  • 構造体の配列を関数に渡すには

    構造体の配列を関数の引数として渡そうとすると エラーになってしまいます ネットで調べてもいまいちわからなかったので ここで質問させてもらいます #include<stdio.h> struct A{   ・    ・    ・ }; void func(struct A *p); int main(void) { struct A x[3][4] = {     ・     ・     ・ }; func(x); return 0; } void func(struct A *p){     ・     ・    ・ } どうすれば渡すことができるのでしょうか? どなたか助言お願いします。

  • &と配列とアドレスについて

    &と配列とアドレスの関係性についての質問です。 以下のような処理を書くと、「a」「&a」「&a[0]」は全て同じ 値をさしてしまいます。 「a」と「&a[0]」が同じなのはわかりますが、「&a」も 同じというのは、なぜでしょうか。 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ int main(void) {  int a[1];  printf("%d\n",a);  printf("%d\n",&a);  printf("%d\n",&a[0]);  return 0; } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  • 2次元配列を引数とする関数について

    2次元配列を引数とする関数について 私は今、2次元配列を引数とする関数の表を作るという課題に取り組んでいます。 条件として、int a[数字][数字]={{1,2,3...}}という配列の宣言と同時の初期化は使わず、 関数内で表の値を代入し、値を表示する関数を作り、事実上二つの関数を作るというものです。 私は以下のようなプログラムを作り、動かしましたが、[数字][数字]=********のような本来 あるべき実行結果とは異なる数字の羅列が出てきてしまいました。 ↓ #include <stdio.h> void func(int a[][6]); void fund(int b[4][6]); void main(void) { int a[4][6]; fund(a); func(a); } void func(int a[][6]) { int i,j,b[4][6]; fund(b); for(i=0;i<4;i++)        { for(j=0;j<6;j++) { printf("a[%d][%d]=%d\n",i,j,a[i][j]); printf("\n"); } } } void fund(int b[4][6]) { int i,j; for(i=0;i<4;i++) { for(j=0;j<6;j++)          { scanf("b[%d]*[%d]=%d\n",&i,j,b[i][j]); } } } 本来の実行結果 1 2 3 4 5 6 2 4 6 8 10 12 3 6 9 12 15 18 4 8 12 16 20 24 紙にも書いて何回も見直しましたが、どこがおかしいのかわかりませんでした。 どうすれば良いのでしょうか? 何か良いアドバイスをよろしくお願いします。

  • 引数に二重配列のある関数について

    void calc(int *a,int b,int c){ a[0]=b+c; a[1]=b-c; } void main(void){ int x[2]; int y=2,z=5; calc(x,y,z); printf("x[0]=%d,x[1]=%d\n",x[0],x[1]); } 上のように引数が普通の配列の関数ならできるのですが, 引数が下のような多重配列になるとエラーが出てしまいできません。 void keisan(int **a,int b,int c){ a[0][0]=b+c; a[0][1]=b-c; a[1][0]=b*c; a[1][1]=b/c; } void main(void){ int x[2][2]; keisan(x,6,2); printf("x[0][0]=%d,x[0][1]=%d\n",x[0][0],x[0][1]); printf("x[1][0]=%d,x[1][1]=%d\n",x[1][0],x[1][1]); } 引数に多重配列を使った場合の関数の作り方について教えてください. お願いいたします.

  • C言語で、他の関数で配列を書き換えられないようにしたい

    下のCのプログラムでは、func関数は配列aの先頭要素へのポインタを返します。 main関数の側では配列aの中身を表示します。 しかし、main関数のfor文の中の★の部分をコメントアウトせずに入れると、この配列の中身が書き換わってしまいます。  私はfunc関数以外では、この配列の中身をいじられたくないのです。  なんとかfunc関数を工夫して作成して、func関数以外では、配列の中身が変わらないようにしたいのですが、どうすればよいでしょうか。    とは言ったものの、多分できないだろうなあ、という気がします。  できないならばできないでも仕方ないのですが、確信が持てないのです。 条件があります。 funcでは表示は行なわない。 配列aの中身を表示できるように、funcから呼び出し元へ、aのアドレスまたはaの先頭要素のアドレスがわかるような情報を返す。 #include <stdio.h> char *func(int i) { static char a[]="AAAA"; a[i]='z'; return a; } int main(void) { int i; for(i=0; i<4; i++) { char *p=func(i); /* p[i]='X'; ★配列の中身を書き換えてしまう。 */ puts(p); } return 0; }

専門家に質問してみよう