アプリ版:「スタンプのみでお礼する」機能のリリースについて

質問です。
配列を使い、その値の合計値を出す際に私はループカウンタを利用して足す手法を
思いつくのですが、それ以外の方法があると聞きました。
ですが、それ以外の方法が思いつかなく質問させてください。

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

for ( int i = 0; i < 10; i++ )
{
nSum += a[i];
}

return nSum;

ここでループカウンタを使用せず、配列の全てを足すにはどうしたら良いでしょうか。

A 回答 (11件中1~10件)

C++なら、No1の回答者さんがおっしゃるようにSTLのaccumulateを


使うのが簡単だと思います。
自分で実装するのであればポインタを使って

for (int *p=a; p<a+10; p++) {
 nSum += *p;
}

のように書くこともできます。
カウンタのほうが分かりやすくてよいと思いますが。
    • good
    • 0
この回答へのお礼

なるほど、ポインタをそのまま当てはめ
pをインクリメントしていくわけですね!

参考にさせていただきます!

お礼日時:2007/02/24 13:27

配列の最後に終端となるデータを設定して



  int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1 };
  int nSum = 0;
  int *p = a;

  for(; *p >= 0; *p++) {
    nSum += *p;
  }

または
  while (*p>=0) {
    nSum += *p++;
  };
    • good
    • 0

#8 さん



> 一番高速という意味では、
> (中略)
> だと思います。

確かに.(^^;
ループアンローリングという手がありましたね.


#9 さん

> x86系CPUなら
> [(ベースアドレス)+(1要素サイズ)*(オフセット)]
> のアドレスに格納されているの値の参照を1クロックで
> 行うことができるので、

そうなんですが,要素サイズは 1,2,4,8 バイト限定ですよね.
今回のように要素が基本データ型ならいいんですが,一般の構造体だと使えない場合が多いですね.
    • good
    • 0

少なくともx86系CPUなら


[(ベースアドレス)+(1要素サイズ)*(オフセット)]
のアドレスに格納されているの値の参照を1クロックで
行うことができるので、ループカウンタを使用することで
遅くなるということはないと思います。
まあ、ループ内で行う処理や最適化の質にもよるでしょうけど。
ループ数が固定なら、コンパイラによってはNo.8のような
形にまで最適化してくれるそうですし。
    • good
    • 0

一番高速という意味では、



int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
return a[0]+a[1]+a[2]+a[3]+a[4]+a[5]+a[6]+a[7]+a[8]+a[9];

だと思います。
一般に、効率を上げるには汎用性を捨てるのが最も効果的です。
    • good
    • 0

★あぁ…間違った!


・noocyte さん、ご指摘有り難う御座います。

●質問者さんへ
・間違い⇒『nSum += *a++;』
・正しい⇒『nSum += *p++;』
・以上。すみませんでした。
    • good
    • 0

#3 です.



#5 さんに先に書かれちゃいましたが,これがたぶん一番高速な
(少なくとも他の方法より遅くはないはず) 方法です.
(なので私はよく使います.)


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

// 以下,#5 さんと実質的に同じコード

const int * const endOfArray = &a[10]; // a[] の直後のアドレスを指す.
const int *element = a; // a[] の要素を指す.

while(element < endOfArray) nSum += *element++;


この方法だと,ループ内の処理は,
(どうせやらないといけない,配列要素の参照と nSum への加算を除けば)
次の2つだけです.
・element < endOfArray の判定
・element++

他方質問文のように,普通にループカウンタを添字にする方法だと,
次の処理が必要です.
・i < 10 の判定
・i++
・i から &a[i] を求める処理.つまり次の2つ.
 size_t offset = sizeof(a[i]) * i; // a[] の先頭に対する a[i] のバイト・オフセット
 const char *address = (char*)a + offset; // a[i] のバイトアドレス

(もっとも,後者はコンパイラが最適化によって
 前者のようなコードに変換してくれるかもしれません.)


#4 さん
> nSum += *a++;

a は定数なのでエラーですよ~.(笑)
    • good
    • 0

★『配列の添え字を使うな!』という事かな?


・それならば、配列をポインタにセットして要素分だけループして加算します。
・これ以外では、私も思い浮かびません。
・下にサンプルを載せます。

サンプル:
int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int *p = a;
int nSum = 0;

for ( int i = 0 ; i < 10 ; i++ ){
 nSum += *a++;
}
return nSum;

最後に:
・配列とポインタの学習ですかね。
・やっぱり『ループカウンタを使用せず』の意味がよく分かりません。
・とりあえず、上記のサンプルをどうぞ。
・以上。おわり。
    • good
    • 0
この回答へのお礼

配列とポインタの学習、その通りです。
使うだけなら、こう使えば動く。としか知らない面が多く
それを実際に職業にしている方から、違う方法もあるよ。と言われたもので・・・

参考にさせていただきます!

お礼日時:2007/02/24 13:25

再帰呼び出しを使う方法もあります.



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

int SumOfArray(const int array[], unsigned nElements)
{
 return (nElements <= 0) ? 0 :
     (array[0] + SumOfArray(array + 1, nElements - 1));
}

int main(void)
{
 int nSum = SumOfArray(a, 10);
 printf("nSum = %d\n", nSum);
 return 0;
}

ループカウンタを使う場合に比べて遅いし,
配列の要素数が非常に多いとスタックオーバーフローしてしまいますが.

/* 私はCよりも先に Lisp を覚えました.(笑) */
    • good
    • 0
この回答へのお礼

おー!こんな方法もあるんですね!
>ループカウンタを使う場合に比べて遅いし,
>配列の要素数が非常に多いとスタックオーバーフローしてしまいますが.

私はまだまだ初心者なので、方法として教えて頂けたのは大変ありがたいです!

お礼日時:2007/02/24 13:23

>ループカウンタを使用せず


というのが配列の要素を指定するのに使わない
という意味なら下記のようにすることができます

配列の最後の要素にストッパーとしての値を入れて
それを検出するまで加算、という風にすればfor文を使わなくても実現できます

-----引用
      /* 正数のカウント */
      for( i = 0; i < inputCount; i++ ){
        if ( *data > 0 ){
          sum = sum + *data;
          count++;
        }
        data++;
      }

http://www.na.rim.or.jp/~m_tanabe/c/pointer8.html
-----引用
    • good
    • 0
この回答へのお礼

>ループカウンタを使用せず
というのが配列の要素を指定するのに使わない
という意味なら下記のようにすることができます

その通りです。言葉が足りずすみません。

引用サイト見てみます!ありがとうございます

お礼日時:2007/02/24 13:21

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!