2009-03-25 23 views
2

私のプログラムでは、動的長さのint配列を使用しなければならず、コード内のさまざまなポイントでその中にあるオブジェクトの数を取得できるようにしたい。私はC++に精通していませんが、ここに私が持っているものがあります。なぜそれは私に正しい長さを与えていないのですか?ありがとう。Int配列の長さC++

<#include <iostream> 
Using Namespace std; 
int length(int*); 


void main() 
{ 
    int temp[0]; 
    temp[0] = 7; 
    temp [1] = 10; 
    temp[2] = '\0'; 

    cout << length(temp) << endl; 
} 

int length(int* temp) 
{ 
    int i = 0; 
    int count = 0; 

    while (*temp + i != '\0') 
    { 
      count++; 
      i++; 
    } 
    return count; 
} 

現在は無限ループに入っています。あなたは試みることができる

+1

を。長さ0の配列を持つことはできません。どのコンパイラを使用していますか? –

答えて

4

while (*(temp + i) != '\0') 

あなたの現在のソリューションは明らかにあなたが欲しいものではありませんこれは、(7+iに等しい)temp[0] + iを計算しています。

15

C++の配列は動的ではありません。 temp配列の長さはゼロです。長さを超えてメンバーに書き込もうとすると、未定義の動作になります。それは、スタックの一部を上書きするので、ほとんど機能しない可能性があります。

固定サイズの配列を作成して、必要なものを配置するのに十分なスペースを確保するか、動的データ構造のstd::vector<int>を使用します。ベクトルの

#include <iostream> 
#include <vector> 
using namespace std; 
int length(int*); 


int main() // error: ‘::main’ must return ‘int’ 
{ 
    int temp[3]; 
    temp[0] = 7; 
    temp[1] = 10; 
    // don't use char constants for int values without reason 
    temp[2] = 0; 

    cout << length(temp) << endl; 

    vector<int> vec_temp; 

    vec_temp.push_back(7); 
    vec_temp.push_back(10); 

    cout << vec_temp.size() << endl; 

} 

int length(int* temp) 
{ 
    int i = 0; 
    int count = 0; 

    while (*(temp + i) != 0) // *temp + i == (*temp) + i 
    { 
      count++; 
      i++; // don't really need both i and count 
    } 
    return count; 
} 

は、開始時にサイズを指定する必要はありません、あなたはゼロを入れて、長さを見つけるのは簡単操作ではなく、ループを必要としていることができます。

ループのもう1つのバグは、配列の最初のメンバーを見て、ポインタをiだけインクリメントするのではなく、その値にiを追加していたことです。

int length(int* temp) 
{ 
    int count = 0; 

    while (*temp != 0) 
    { 
      ++count; 
      ++temp; 
    } 

    return count; 
} 

またはインデックスの一時に数を使用して::

int length(int* temp) 
{ 
    int count = 0; 

    while (temp[count] != 0) 
      ++count; 

    return count; 
} 
0

ダイナミック取得するにはあなたは本当に私と数えるので、他のいくつかの方法ことを書くことができ、直接温度をインクリメントし、両方の必要はありません。配列内の行動、std::vectorを使用するか、または手動のメモリ割り当て(newdelete)でint *を使用して戻って古い学校のCスタイルの秋[*]

[*] Cの実装では、(文字配列aの文脈で議論s C dynamic string length)はmalloc,reallocおよびfreeですが、これらはC++コードでは使用しないでください。

+0

なぜ新しい&deleteではなくmalloc&realloc(そしておそらくフリー)を使いたいのですか? –

+0

@Neil:良い点。私はcのことを考えていた。しかし、もし彼がC++スタイルをしているのであれば、std :: vectorよりもint *アプローチを選択するケースはほとんどありません。 – dmckee

5

このアプローチはいくつかの理由悪い考えですが、最初にここにいくつかの問題があります:

int temp[0]; 

は、これは私がスタック要素に許可されていても思いません0アイテム、の配列です。このような配列を宣言する場合は、使用する値の最大値を指定する必要があります。 int temp[10];

これは非常に重要です! - 数字を少なく(例えば[10]と[11]を使用すると)指定すると、最高でクラッシュし、最悪の場合、悪夢である不思議なバグが追跡されるメモリ上書きが発生します。

次の問題は、この行です:この行がないこと

while (*temp + i != '\0') 

「TEMP」で指定されたアドレスの値が格納を取ると私を追加しています。何がしたいことはそうのように、温度によって指定されたアドレスのn番目の要素に値を取得することです:

while (*(temp + i) != '\0') 

だから、何が間違っているのですが、あなたはこれを行うには良い方法を考えるために5分を取る必要があります。

私はそれが悪いアイデアだ言及した理由は以下のとおりです。

  • あなたは(この場合は0)で終端素子を保存することはできませんあなたがその長さ
  • を必要とし、アレイ全体のいつを反復する必要がで配列

代わりに、配列の要素数を格納する別の値を維持することをお勧めします。これを行う最も一般的な方法は、この概念(要素のブロックと現在のサイズ)をラップするクラスを作成することです。

C++標準ライブラリには、この目的で使用できる "vector"という名前のテンプレートクラスが付属しています。配列と全く同じではありません(索引付けする前に項目を追加する必要があります)が、非常に似ています。また、便利なコピー/リサイズのサポートも提供しています。

ここにstd :: vectorを使用するように書かれたプログラムがあります。代わりに、「長さ」関数の私は値をプリントアウトするために何かを追加しました:

#include <vector> 
#include <iostream> 

void print(std::vector<int> const& vec) 
{ 
    using namespace std; 

    for (size_t i = 0; i < vec.size(); i++) 
    { 
     cout << vec[i] << " "; 
    } 

    cout << endl; 
} 

int main() 
{ 
    std::vector<int> temp; 
    temp.push_back(7); 
    temp.push_back(10); 

    print(temp); 

    return 0; 
} 
+0

'int temp [0]'は許されています。アレイの有効なアドレスが存在するだけで、実際に何かを指しているわけではありません。 – greyfade

3

をピートが指摘するようにだけでなく、C++の配列は動的ではありませんが、文字列だけ(のchar *)が「\ 0」で終了します。 (これは、他のタイプにも同様の規約を使用することはできないと言っているのではなく、むしろ異例のことです。特に、ターミネーターシンボルを使用すると、配列をループしてサイズを調べる必要があります)

あなたのような場合は、標準ライブラリを使用する方がよいでしょう。

#include <vector> 
#include <iostream> 

int main() 
{  
    std::vector<int> v; 
    v.push_back(7); 
    v.push_back(10); 
    std::cout << v.size() << std::endl; 
    return 0; 
} 
+0

「\ 0」を他のデータ型のセンチネルとして使用するための規約を決めることができなかったのはなぜですか? (たとえそれが一般的に使われていないとしても) – Reunanen

+0

(intに '\ 0'を代入しても誤解を招いていますが、とにかく0になります。まだそれが最良の方法ではないにもかかわらずうまくいくはずです) – Reunanen

+0

@Pukku:あなたはそのような大会を決めることはできません。文字列の場合、ライブラリによって強制される規則だけでなく、文字列リテラルは自動的に末尾に '\ 0'を含みます。これは例えば配列のリテラルでは当てはまりません。 – UncleZeiv

0

ゼロ要素の配列にのみスペースを割り当てるためです。 次の行

temp [1] = 10; 
    temp[2] = '\0'; 

は、より多くのメモリを割り当てるか、アレイのサイズを変更しません。配列の外側にデータを書き込むだけで、アプリケーション状態の他の部分が破損します。それをしないでください。 ;)

あなたがサイズ変更可能な配列をしたい場合、あなたはSTDを使用することができます::ベクトル(と新しい値を挿入するために一backメンバ関数を使用)

ベクターはまた、あなたに伝えサイズ()メンバ関数を持っています現在のサイズ。

プリミティブアレイを使用する場合は、自分でサイズを追跡する必要があります。(と、配列のサイズを変更する場合が必要である、新しい、1より大きいに古い配列からすべての要素をコピーする)固定長の配列のサイズを取得するための最も一般的な方法は、このようなものである

1

int temp[256]; 
int len = sizeof (temp)/sizeof (temp[0]); 
// len == 256 * 4/4 == 256 on many platforms. 

実際にはポインタなので、動的配列では機能しません。

int* temp = new int[256]; 
int len = sizeof (temp)/sizeof (temp[0]); 
// len == 4/4 == 1 on many platforms. 

サイズを気にする場合は、動的長さの配列の場合は、配列を割り当てるときにどこかに格納するのが最良です。多くの人が指摘したように

あなたのループの問題は、あなたがここで演算子の優先順位の問題を抱えているということです。

*temp + i 

は次のようになります。

*(temp + i) 

しかし、大きな問題も指摘ポインタの長さと固定長の配列を理解していないように見え、配列の最後を書き去っているということです。

1

アレイを正しく使用するには、値を格納するのに十分なメモリを割り当てる必要があります。長さを指定すると、その長さを変更することはできません。配列のサイズを知るためには、例えば、変数に格納する必要があります。:

int n; 
cin>>n; 
int array = new int[n]; 
int array_length=n; 

あなたは、配列の長さを変更したい場合は、最良の方法は、例えばのstd ::ベクトルのために、STDのコンテナを使用することです。あなたがのstd ::ベクトルを使用しない場合

2

、これを試してみてください。

#include <iostream> 
using namespace std; 

int main() { 
    int vet[] = {1,2,3,4,5,6}; 
    cout << (sizeof (vet)/sizeof *(vet)) << endl; 
    return 0; 
} 
-1

はこれを試してみてください:コンパイルされていないはず

int length(int* temp) 
{ 
    int count = 0; 

    while (*temp != 0 && *temp != -858993460) 
    { 
     ++count; 
     ++temp; 
    } 

    return count; 
}