2017-01-24 12 views
0

次の関数「インクリメント」は配列として表される数に1を加算します。関数からの可変長配列の返却

int* increment(int array[], int size, int *sizeLen) 
{ 
    int temp[size+1]; 

    int carry = 0; 
    carry = (array[size-1]+1)/10; 
    temp[size] = (array[size-1]+1)%10; 

    for(int i=size-2;i>=0;i--) 
    { 
     temp[i+1] = (array[i] + carry)%10; 
     carry = (array[i]+carry)/10; 
    } 
    if(carry) 
    { 
     temp[0] = 1; 
     *sizeLen = size+1; 
     return temp; 
    } 
    else 
    { 
     *sizeLen = size; 
     return (temp+1); 
    } 
} 

int main() 
{ 
    int array[] = {9,9,9}; 
    int length; 
    int *res = increment(array, sizeof(array)/sizeof(int), &length); 
    for(int i=0;i<length;i++) 
    { 
     cout << res[i] << " "; 
    } 
} 

私はgccがvariable length arraysをサポートしていて、スタックに格納されていることを知っています。 この関数が終了するとtempが範囲外になることが予想され、mainに配列を出力しようとするとガベージ値が出力されるはずです。 私の場合、実際の値が表示されます。 関数内で宣言された可変長配列は、いつスコープから外れますか?

+6

あなたが見ているのは未定義の動作です。それはCの落とし穴です。 –

+1

C++はVLAをサポートしていません。あなたのコードは基本的にCです。コンテナとイテレータを使用してください。 – Downvoter

+0

私はタグを気付かなかった。 VLAをC++コード(拡張機能、非標準)で使用しているのはなぜですか?あなたの質問は本当にCについてですか?明確化してください。それらは異なる言語です。 – StoryTeller

答えて

0

ここで重要なのは、実際にはアレイの保存期間です。自動保存期間があります。自動保存期間を持つ変数の有効期間は、有効範囲が終了した瞬間に終了します。

これはまさに期待通りです。しかし、Cの中には、ローカルオブジェクトのアドレスを取得して関数から返すことを止めるものはありません。

このポインタを使用することは、未定義の動作です。それは動作するように見えるかもしれませんが、配列はまだすべての意図と目的のために "死んでいる"ためです。そのようなポインターは、「ぶら下がりのポインター」として口語的に知られている。これはGCCの拡張機能についてですので


まあは、上記と同じはほとんど適用されますが、塩の粒で撮影する必要があるかもしれない、C.についても同様です。

0

これは未定義の動作です。次にプログラムがスタックにプッシュすると、データは失われます。

専門的なプログラムにはこれを頼りにしないでください。

+0

私の簡潔さを許してください。私は現在Androidのタブレット上にいる。 –

0

あなたは正しいです。 tempは範囲外になり、ガベージ値が出力されるはずです。

しかし、正しい値が表示されることがあります。現在の関数が終了するとすぐにローカルスタックメモリがクリア/オーバーライドされないためです。

1

これは機能しません。ローカル配列へのポインタを返しています。このポインタは、関数が返るとすぐに削除されます(オーバーライト/再利用される可能性が高い)。

このようなことを行うC++の方法は、std::vector<>を使用することです。あなたが他の数字の順序を定義していた場合、あなたのコードは非常に簡単になることを例えば(元sizesizelenにそれぞれ、array内の要素の数を参照し、返されたと仮定して)

std::vector<int> increment(std::vector<int> const&array) 
{ 
    std::vector<int> temp(array.size()); 
    auto a = array.rbegin(); 
    auto b = temp.rbegin(); 
    auto carry = (*a+1)/10; 
    *b = (*a+1)%10; 
    for(++a,++b; a!=array.rend(); ++a,++b) 
    { 
     *b = (*a+carry)%10; 
     carry = (*a+carry)/10; 
    } 
    if(carry) { // we must add another element into temp at the start 
       // that cannot be done with vector, hence we must create 
       // another vector. Note that this should rarely happen. 
     std::vector<int> result(temp.size()+1); 
     auto r = result.begin(); 
     *r = 1; 
     std::copy(temp.begin(),temp.end(),++r); 
     return result; 
    } else 
     return temp; 
} 

注意すなわち、最下位桁を第1の要素(インデックス0)とする。さらに、あなたの数字が小数に見えるので、intより小さいタイプを使用できます。この場合、コードは次のようになります

std::vector<std::uint8_t> increment(std::vector<std::uint8_t> const&input) 
{ 
    std::vector<std::uint8_t> result; 
    result.reserve(input.size()+1); 
    auto a = input.begin(); 
    auto carry = (*a+1)/10; 
    result.push_back((*a+1)%10); 
    for(++a; a!=input.end(); ++a) 
    { 
     result.push_back((*a+carry)%10); 
     carry = (*a+carry)/10; 
    } 
    if(carry) 
     result.push_back(1); 
    return result; 
} 
+0

'if(carry)temp.insert(1、temp.begin());'の何が問題なのですか?それはすべての要素をシャッフルすることを伴いますが、実装するコピーよりも悪くありません。 –

+0

また、 'carry'を1に初期化してループを' do-while'にすると、すべてが 'std :: vector result(array);'(または、値で配列を取ります。入力が一時的な場合)。 'intキャリー= 1;自動it = result.rbegin(); do {auto v = * it + carry; * it ++ = v%10;キャリー= v/10; –

+0

ああ、空の入力ではうまく動作しません。 '(キャリー&& it!= result.rend())if(carry){result.insert(carry、result.begin();} (自動)=(それはキャリー=&gt;それはキャリー=&gt;/10;} if(carry){result.insert(carry、result.begin();}結果を返します; –

関連する問題