関数で配列を返す


212

int arr[5]関数に渡される配列がありますfillarr(int arr[])

int fillarr(int arr[])
{
    for(...);
    return arr;
}
  1. どうすればその配列を返すことができますか?
  2. ポインターを返したとしたら、どのように使用しますか?

46
このコンテキストで厳密に言えば、配列は参照によって渡されるため、配列を返す必要はありません。そのため、「arr」内の要素に対する変更は、関数の外側で確認できます。
BuggerMe 2010

12
配列を返すことは、関数の連鎖に便利です。
2010

5
スタック上に配列を作成し、その配列へのポインターを返すミスを犯していない限り。
10

2
@ismail:新しい配列を動的に割り当てない限り、その配列を返すことはできません。その場合は、を使用してくださいstd::vector
GManNickG

4
@BuggerMe:配列は参照によって渡されません(非常に面白い構文で要求しない限り)。コードでは、配列は最初の要素へのポインターに減衰し、それが関数に渡されます。5関数のシグネチャでは、コンパイラによって破棄されます。
デビッドロドリゲス-10

回答:


204

この場合、配列変数arrは、暗黙的な変換によって、メモリ内の配列のブロックの先頭へのポインターとして実際に処理することもできます。あなたが使用しているこの構文:

int fillarr(int arr[])

一種の構文糖です。あなたは本当にこれに置き換えることができ、それでも動作します:

int fillarr(int* arr)

したがって、同じ意味で、関数から返したいのは、実際には配列の最初の要素へのポインタです。

int* fillarr(int arr[])

また、通常の配列と同じように使用できます。

int main()
{
  int y[10];
  int *a = fillarr(y);
  cout << a[0] << endl;
}

45
明確にするために、「従来のC ++ステートメント」は誤りです。配列はポインタではありません。
GManNickG 2010

25
a [i] == *(a + i)ルールを
思い出してください

8
@ブレントナッシュ、いいえ。配列は配列です。配列の先頭へのポインターはポインターです。コンパイラーには、状況によっては変換を実行する構文糖が含まれている場合があります。 arrayそして&array多くのケースで交換可能です。
Carl Norum、2013

20
@ブレント:いいえ。配列は独自の型であり、特別な種類のポインタではありません。タイプaではint a[10]ありますint[10]。あなたが言うことができることは、それらの最初の要素へのポインターへの配列「崩壊」です。(これは暗黙の配列からポインターへの変換です。)次に、あなたの答えは私のものに沿ったものになります。配列、配列からポインターへの変換、およびポインターを区別するために回答を編集する場合、それらは同じコア情報を持ち、あなたが最初だったので、私の回答を削除します。
GManNickG 2010

8
@seand a [i] == *(a + sizeof(a)* i)ルール
アミール

114

C ++関数は、Cスタイルの配列を値で返すことはできません。最も近いのは、ポインタを返すことです。さらに、引数リストの配列型は、単純にポインターに変換されます。

int *fillarr( int arr[] ) { // arr "decays" to type int *
    return arr;
}

引数と戻り値の配列参照を使用して、減衰を防ぐことにより、これを改善できます。

int ( &fillarr( int (&arr)[5] ) )[5] { // no decay; argument must be size 5
    return arr;
}

BoostまたはC ++ 11では、参照渡しはオプションであり、構文はそれほど難しくありません。

array< int, 5 > &fillarr( array< int, 5 > &arr ) {
    return arr; // "array" being boost::array or std::array
}

arrayテンプレートは、単純に発生structしますが、オブジェクト指向のセマンティクスを適用し、まだ配列のオリジナルのシンプルさを維持することができますので、含むCスタイルの配列を。


4
参照によって配列を渡す方法の例を示す+1。しかし、あなたは参照によって配列を返すことができないという点で間違っています。これを実現する最も簡単な構文は、typedefを使用することです。typedef int array[5]; array& foo();ただしint (&foo())[5] { static int a[5] = {}; return a; }、これを記述したい場合はtypedefも必要ありませんint (&foo( int (&a)[5] ))[5] { return a; }。質問の例は次のようになります。簡単ですね。
デビッドロドリゲス-10

@David:おかげで、error: function returning array is not allowedtypedef以外の構文で外側の括弧を省略した場合に発生するコモーメッセージから誤解を受けました。幸いなことに、今日、私は別の質問の右左規則を確認し、正しいことを構築することができました...可能だとあなたが見た後...コード:vPを与えることを見る前に。
Potatoswatter 2010

1
chubsdadによる答えには、標準からの正しい引用があります。配列を返すことはできませんが、配列への参照またはポインターを返すことはできます。配列は(型として)コピー不可であり、そのため返されない(コピーを意味する)ため、その構文が存在する場合、コンパイラーは引数をポインターに変換します。
デビッドロドリゲス-ドリベス

3
@David:そうです。このページは奇妙に長くなってきています。1つの場所で配列を返す非常に多くの自明な関数を自発的に記述した人は決して多くありません。
Potatoswatter 2010

@Potatoswatter cppは初めてですが、2番目のコードスニペットを詳しく説明できますか?理解のために分割することはできません。
KPMG

23

C ++ 11では、を返すことができますstd::array

#include <array>
using namespace std;

array<int, 5> fillarr(int arr[])
{
    array<int, 5> arr2;
    for(int i=0; i<5; ++i) {
        arr2[i]=arr[i]*2;
    }
    return arr2;
}

2
引用OP:(...) you can consider the array returned arr2, totally another array (...)
cubuspl42 2014年

22

$ 8.3.5 / 8州-

「関数は、型の戻り値の型の配列または関数を持たないものとします。ただし、戻り値の型のポインターまたはそのようなものへの参照が含まれる場合があります。関数へのポインターの配列があっても、関数の配列は存在しません。」

int (&fn1(int (&arr)[5]))[5]{     // declare fn1 as returning refernce to array
   return arr;
}

int *fn2(int arr[]){              // declare fn2 as returning pointer to array
   return arr;
}


int main(){
   int buf[5];
   fn1(buf);
   fn2(buf);
}

7
2番目の関数はint、配列ではなくへのポインタを返します。
GManNickG 2010

繰り返しますが、実際の配列が関数内で更新されたときに型を返すのはなぜですか?それはベストプラクティスの問題ですか?
Dan

14

答えは、その関数をどのように使用するかによって多少異なります。最も単純な答えとして、配列の代わりに本当に必要なのはベクトルであると決定しましょう。退屈で通常のポインタに格納できる通常の値のように、すべての世界を探すことができるので、ベクトルは素晴らしいです。他のオプションとその理由を後で説明します。

std::vector<int> fillarr( std::vector<int> arr ) {
    // do something
    return arr;
}

これにより、期待どおりの結果が得られます。利点は、std::vectorすべてがクリーンに処理されるようにすることです。欠点は、配列が大きい場合、非常に大量のデータをコピーすることです。実際には、配列のすべての要素を2回コピーします。最初に、関数がパラメーターとして使用できるようにベクターをコピーします。次に、それを再度コピーして、呼び出し元に返します。ベクトルの管理を自分で処理できれば、かなり簡単に処理を実行できます。(呼び出し側がより多くの計算を行うために何らかの種類の変数に保存する必要がある場合、3回目にコピーする可能性があります)

あなたが本当にやろうとしているのは、単にコレクションにデータを追加することです。コレクションの新しいインスタンスを返す特別な理由がない場合は、そうしないでください。このようにできます

void fillarr(std::vector<int> &  arr) {
    // modify arr
    // don't return anything
}

この方法では、関数のプライベートコピーではなく、関数に渡された配列への参照を取得します。パラメータに加えた変更は、呼び出し元に表示されます。必要に応じてそれへの参照を返すこともできますが、これは実際には素晴らしいアイデアではありません。これは、渡したものとは異なるものを取得していることを意味しているためです。

コレクションの新しいインスタンスが本当に必要であるが、それをスタック(およびそれに伴うすべてのコピー)に配置したくない場合は、そのインスタンスの処理方法について何らかの契約を作成する必要があります。これを行う最も簡単な方法は、スマートポインターを使用することです。これにより、誰かがそのインスタンスを保持している限り、参照されているインスタンスが保持されます。範囲外になると、問題なく削除されます。それはこのようになります。

std::auto_ptr<std::vector<int> > fillarr( const std::vector<int> & arr) {
    std::auto_ptr<std::vector<int> > myArr(new std::vector<int>);
    // do stuff with arr and *myArr
    return myArr;
}

ほとんどの場合、使用*myArr方法は、単純なバニラベクトルを使用する方法と同じです。この例では、constキーワードを追加してパラメーターリストを変更します。これで、コピーせずに参照を取得できますが、変更することはできないため、呼び出し元は、関数が取得する前と同じであることを認識しています。

これらすべてはうねりですが、慣用的なc ++がコレクション全体で動作することはほとんどありません。より一般的には、これらのコレクションに対してイテレータを使用します。それはこのように見えるでしょう

template <class Iterator>
Iterator fillarr(Iterator arrStart, Iterator arrEnd) {
    Iterator arrIter = arrStart;
    for(;arrIter <= arrEnd; arrIter++)
       ;// do something
    return arrStart;
}

このスタイルを見るのに慣れていない場合は、少し奇妙に見えます。

vector<int> arr;
vector<int>::iterator foo = fillarr(arr.begin(), arr.end());

fooは変更されたの先頭を「指す」ようになりましたarr

これの本当に素晴らしいところは、ベクトルでもプレーンC配列や他の多くのタイプのコレクションと同じようにうまく機能することです。たとえば、

int arr[100];
int *foo = fillarr(arr, arr+100);

これは今、この質問の他の場所で示されている単純なポインタの例に非常によく似ています。


構文が間違っている、&シンボルがタイプした後に表示されなければなりません:void fillarr(std::vector<int> & arr)
デビッド・ロドリゲス- dribeas

9

この:

int fillarr(int arr[])

実際には次と同じように扱われます:

int fillarr(int *arr)

本当に配列を返したい場合は、その行を次のように変更できます

int * fillarr(int arr[]){
    // do something to arr
    return arr;
}

実際には配列を返していません。配列アドレスの先頭へのポインタを返しています。

ただし、配列を渡すときは、ポインタのみを渡すことを覚えておいてください。したがって、配列データを変更すると、実際には、ポインターが指しているデータが変更されます。したがって、配列を渡す前に、変更した結果がすでに外側にあることを理解する必要があります。

例えば

int fillarr(int arr[]){
   array[0] = 10;
   array[1] = 5;
}

int main(int argc, char* argv[]){
   int arr[] = { 1,2,3,4,5 };

   // arr[0] == 1
   // arr[1] == 2 etc
   int result = fillarr(arr);
   // arr[0] == 10
   // arr[1] == 5    
   return 0;
}

このような長さをfillarr関数に入れることを検討することをお勧めします。

int * fillarr(int arr[], int length)

そうすれば、長さがどのようなものであっても、配列をその長さに満たすことができます。

実際にそれを適切に使用するため。このようなことをしてください:

int * fillarr(int arr[], int length){
   for (int i = 0; i < length; ++i){
      // arr[i] = ? // do what you want to do here
   }
   return arr;
}

// then where you want to use it.
int arr[5];
int *arr2;

arr2 = fillarr(arr, 5);

// at this point, arr & arr2 are basically the same, just slightly
// different types.  You can cast arr to a (char*) and it'll be the same.

配列をデフォルト値に設定するだけの場合は、組み込みのmemset関数の使用を検討してください。

次のようなもの:memset((int *)&arr、5、sizeof(int));

でも、私はその話題についています。あなたはC ++を使っていると言います。stlベクトルの使用をご覧ください。コードはより堅牢になる可能性があります。

チュートリアルはたくさんあります。これらは、それらを使用する方法のアイデアを与えるものです。 http://www.yolinux.com/TUTORIALS/LinuxTutorialC++STL.html


std::copy以上を使用するとmemset、より安全で簡単になります。(そして、より速くなくても同じくらい速く。)
GManNickG '08 / 08/13

5

関数から配列を返すには、その配列を構造体で定義してみましょう。だからこんな感じ

struct Marks{
   int list[5];
}

次に、タイプ構造の変数を作成します。

typedef struct Marks marks;
marks marks_list;

次の方法で配列を関数に渡し、それに値を割り当てることができます。

void setMarks(int marks_array[]){
   for(int i=0;i<sizeof(marks_array)/sizeof(int);i++)
       marks_list.list[i]=marks_array[i];
}

配列を返すこともできます。配列を返すには、関数の戻り値の型は構造体型、つまりマークでなければなりません。これは、実際には配列を含む構造体を渡すためです。したがって、最終的なコードは次のようになります。

marks getMarks(){
 return marks_list;
}

5

これはかなり古い質問ですが、答えはたくさんあるので、2セントで説明しますが、すべての可能な方法を明確かつ簡潔な方法で示していません(簡潔なビットについてはわかりません。少し手に負えない。TL; DR😉)。

OPが、コピーせずに渡された配列を、呼び出し元に直接渡して別の関数に渡してコードをきれいに見せるための手段として返したいと思っていると思います。

ただし、このような配列を使用することは、それをポインターに減衰させ、コンパイラーに配列のように処理させることです。これは、5つの要素があることを期待する関数などの配列を渡す場合、微妙なバグを引き起こす可能性がありますが、呼び出し元は実際には他の数値を渡します。

これをよりよく処理できる方法がいくつかあります。std::vectororを渡しますstd::arraystd::array質問が行われたときに2010年頃かどうかはわかりません)。その後、オブジェクトをコピー/移動せずに、オブジェクトを参照として渡すことができます。

std::array<int, 5>& fillarr(std::array<int, 5>& arr)
{
    // (before c++11)
    for(auto it = arr.begin(); it != arr.end(); ++it)
    { /* do stuff */ }

    // Note the following are for c++11 and higher.  They will work for all
    // the other examples below except for the stuff after the Edit.

    // (c++11 and up)
    for(auto it = std::begin(arr); it != std::end(arr); ++it)
    { /* do stuff */ }

    // range for loop (c++11 and up)
    for(auto& element : arr)
    { /* do stuff */ }

    return arr;
}

std::vector<int>& fillarr(std::vector<int>& arr)
{
    for(auto it = arr.begin(); it != arr.end(); ++it)
    { /* do stuff */ }
    return arr;
}

ただし、C配列を使用する場合は、配列内の項目数の情報を保持するテンプレートを使用してください。

template <size_t N>
int(&fillarr(int(&arr)[N]))[N]
{
    // N is easier and cleaner than specifying sizeof(arr)/sizeof(arr[0])
    for(int* it = arr; it != arr + N; ++it)
    { /* do stuff */ }
    return arr;
}

それを除いて、それはお尻が醜く、非常に読みにくいです。私は今、2010年にはなかったものを支援するために何かを使用します。これは関数ポインターにも使用します。

template <typename T>
using type_t = T;

template <size_t N>
type_t<int(&)[N]> fillarr(type_t<int(&)[N]> arr)
{
    // N is easier and cleaner than specifying sizeof(arr)/sizeof(arr[0])
    for(int* it = arr; it != arr + N; ++it)
    { /* do stuff */ }
    return arr;
}

これは、1つは、この作り、それがために期待するタイプの移動はるかに読みやすくします。もちろん、5つの要素以外を使用する予定がない場合は、テンプレートを使用する必要はありません。そのため、当然、ハードコードすることができます。

type_t<int(&)[5]> fillarr(type_t<int(&)[5]> arr)
{
    // Prefer using the compiler to figure out how many elements there are
    // as it reduces the number of locations where you have to change if needed.
    for(int* it = arr; it != arr + sizeof(arr)/sizeof(arr[0]); ++it)
    { /* do stuff */ }
    return arr;
}

私が言ったように、type_t<>この質問がなされたとき、私のトリックはうまくいかなかったでしょう。当時あなたが望んでいた最高のものは、構造体で型を使用することでした:

template<typename T>
struct type
{
  typedef T type;
};

typename type<int(&)[5]>::type fillarr(typename type<int(&)[5]>::type arr)
{
    // Prefer using the compiler to figure out how many elements there are
    // as it reduces the number of locations where you have to change if needed.
    for(int* it = arr; it != arr + sizeof(arr)/sizeof(arr[0]); ++it)
    { /* do stuff */ }
    return arr;
}

見た目はかなり醜くなりますが、少なくとも読みやすいtypenameですが、コンパイラによってはオプションであったため、次のような結果になりました。

type<int(&)[5]>::type fillarr(type<int(&)[5]>::type arr)
{
    // Prefer using the compiler to figure out how many elements there are
    // as it reduces the number of locations where you have to change if needed.
    for(int* it = arr; it != arr + sizeof(arr)/sizeof(arr[0]); ++it)
    { /* do stuff */ }
    return arr;
}

そしてもちろん、私のヘルパーを使用するのではなく、特定のタイプを指定することもできます。

typedef int(&array5)[5];

array5 fillarr(array5 arr)
{
    // Prefer using the compiler to figure out how many elements there are
    // as it reduces the number of locations where you have to change if needed.
    for(int* it = arr; it != arr + sizeof(arr)/sizeof(arr[0]); ++it)
    { /* do stuff */ }
    return arr;
}

当時、自由な機能std::begin()std::end()存在していなかったが、しかし容易に実装されている可能性が。これは、C配列では意味があるがポインタでは意味がないため、より安全な方法で配列を反復できるようになります。

配列へのアクセスに関しては、同じパラメーター型を取る別の関数に渡すか、またはエイリアスを作成することができます(スコープに元のオブジェクトがあるため、あまり意味がありません)。配列参照へのアクセスは、元の配列へのアクセスと同じです。

void other_function(type_t<int(&)[5]> x) { /* do something else */ }

void fn()
{
    int array[5];
    other_function(fillarr(array));
}

または

void fn()
{
    int array[5];
    auto& array2 = fillarr(array); // alias. But why bother.
    int forth_entry = array[4];
    int forth_entry2 = array2[4]; // same value as forth_entry
}

要約すると、配列を繰り返し処理する場合は、配列がポインタに分解されないようにすることをお勧めします。コンパイラーが足元から自分を撃たれるのを防ぎ、コードが読みにくくなるため、これは単に悪い考えです。コンパイラは、そうしないようにする十分な理由がない限り、型をできる限り長く保つことで、コンパイラが役立つように常に努めてください。

編集する

ああ、そして完全を期すために、ポインターに分解することを許可できますが、これにより、配列が保持する要素の数から配列が分離されます。これはC / C ++で多く行われ、通常は配列の要素数を渡すことで軽減されます。ただし、誤って要素の数に誤った値を渡した場合、コンパイラーは役に立ちません。

// separate size value
int* fillarr(int* arr, size_t size)
{
    for(int* it = arr; it != arr + size; ++it)
    { /* do stuff */ }
    return arr;
}

サイズを渡す代わりに、配列の終わりを過ぎたところを指す終了ポインターを渡すことができます。これは、開始ポインタと終了ポインタを取るstdアルゴリズムに近いものを作成するのに役立ちますが、返されるのは覚えておかなければならないものだけです。

// separate end pointer
int* fillarr(int* arr, int* end)
{
    for(int* it = arr; it != end; ++it)
    { /* do stuff */ }
    return arr;
}

または、この関数は5つの要素しかとらないことを文書化し、関数のユーザーが愚かなことをしないようにできます。

// I document that this function will ONLY take 5 elements and 
// return the same array of 5 elements.  If you pass in anything
// else, may nazal demons exit thine nose!
int* fillarr(int* arr)
{
    for(int* it = arr; it != arr + 5; ++it)
    { /* do stuff */ }
    return arr;
}

戻り値は元の型を失い、ポインターに劣化していることに注意してください。このため、アレイをオーバーランしないようにする必要があります。

std::pair<int*, int*>beginとendに使用できるを渡し、それを渡すことができますが、実際には配列のように見えなくなります。

std::pair<int*, int*> fillarr(std::pair<int*, int*> arr)
{
    for(int* it = arr.first; it != arr.second; ++it)
    { /* do stuff */ }
    return arr; // if you change arr, then return the original arr value.
}

void fn()
{
    int array[5];
    auto array2 = fillarr(std::make_pair(&array[0], &array[5]));

    // Can be done, but you have the original array in scope, so why bother.
    int fourth_element = array2.first[4];
}

または

void other_function(std::pair<int*, int*> array)
{
    // Can be done, but you have the original array in scope, so why bother.
    int fourth_element = array2.first[4];
}

void fn()
{
    int array[5];
    other_function(fillarr(std::make_pair(&array[0], &array[5])));
}

面白いことに、これはstd::initializer_list機能(c ++ 11)と非常によく似ていますが、このコンテキストでは機能しません。


3

これを行う最も簡単な方法は、参照によって返すことです。「&」記号を記述しなくても、参照によって自動的に返されます

     void fillarr(int arr[5])
  {
       for(...);

  }

2
int *fillarr(int arr[])

あなたはまだ次のような結果を使うことができます

int *returned_array = fillarr(some_other_array);
if(returned_array[0] == 3)
    do_important_cool_stuff();

「int [] fillarr ...」は合法だとは思いません。'int * fillarr'は、配列ポインターの同等性のために使用するものです。
2010

1

上記のようにパスは正しいです。しかし、関数のローカル配列変数だけを返す場合、その要素としてガベージ値が返されることがあります。

配列を動的に作成して続行する必要があることを避けるために。こんな感じです。

int* func()
{
  int* Arr = new int[100];
  return Arr;
}

int main()
{
  int* ArrResult = func();
  cout << ArrResult[0] << " " << ArrResult[1] << endl;
  return 0;
} 




0
template<typename T, size_t N>
using ARR_REF = T (&)[N];

template <typename T, size_t N>
ARR_REF<T,N> ArraySizeHelper(ARR_REF<T,N> arr);

#define arraysize(arr) sizeof(ArraySizeHelper(arr))


0

ソース:https : //www.tutorialspoint.com/cplusplus/cpp_return_arrays_from_functions.htm

C ++では、配列全体を関数の引数として返すことはできません。ただし、インデックスなしで配列の名前を指定することにより、配列へのポインターを返すことができます。

  1. 関数から1次元配列を返す場合は、次の例のように、ポインターを返す関数を宣言する必要があります。
int * myFunction()    {
   .
   .
   .
}
  1. C ++はローカル変数のアドレスを関数の外部に返すことを推奨していないため、ローカル変数を静的変数として定義する必要があります。

これらのルールを現在の質問に適用すると、次のようにプログラムを作成できます。

# include <iostream>

using namespace std;

int * fillarr( );


int main ()
{

   int *p;

   p = fillarr();

   for ( int i = 0; i < 5; i++ )
       cout << "p[" << i << "] : "<< *(p + i) << endl;

    return 0;
}


int * fillarr( )
{
    static int  arr[5];

    for (int i = 0; i < 5; ++i)
        arr[i] = i;

    return arr;
 }

出力は次のようになります。

p[0]=0
p[1]=1
p[2]=2
p[3]=3
p[4]=4

0

そして何について:

int (*func())
{
    int *f = new int[10] {1,2,3};

    return f;
}

int fa[10] = { 0 };
auto func2() -> int (*) [10]
{
    return &fa;
}

0

実際に、関数内で配列を渡すと、元の配列へのポインターが関数パラメーターで渡されるため、その関数内の配列に加えられた変更は、実際には元の配列に対して行われます。

#include <iostream>

using namespace std;

int* func(int ar[])
{
    for(int i=0;i<100;i++) 
        ar[i]=i;
    int *ptr=ar;
    return ptr;
}


int main() {
    int *p;
    int y[100]={0};    
    p=func(y);

    for(int i=0;i<100;i++) 
        cout<<i<<" : "<<y[i]<<'\n';
}

それを実行すると、変更が表示されます


1
適切な英語の表現を使用し(u'llの代わりに使用します)、「buddy」などの空のフレーズは省略してください。
2018

また、「実際には参照として渡されます」は誤りです。変数y自体はそれ自体のコピーとして渡されますが、これはポインターであるため、配列を直接操作します。回答を編集してください。
2018

stackoverflow.com/questions/5573310/…TL ; DR 「このように、2つの形式は同じです。」
中空の

はい、技術的には配列です。そうですが、コピーされるのは配列自体ではなく、配列へのポインタです。
中空の

0

これが解決するこの種の問題の完全な例です

#include <bits/stdc++.h>
using namespace std;
int* solve(int brr[],int n)
{
sort(brr,brr+n);
return brr;
}

int main()
{
int n;
cin>>n;
int arr[n];
for(int i=0;i<n;i++)
{
    cin>>arr[i];
}
int *a=solve(arr,n);
for(int i=0;i<n;i++)
{
    cout<<a[i]<<endl;
}

return 0;
}

-2

type []を戻り値として定義するだけです:

        private string[] functionReturnValueArray(string one, string two)
    {

        string[] x = {one, two};


        x[0] = "a";
        x[1] = "b";

        return x;
    }

。。。関数呼び出し:

string[] y;
y = functionReturnValueArray(stringOne, stringTwo)

5
これはC ++ではありません
Adrian
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.