2009-08-20 13 views
0

ほとんどの高水準言語(Python、Ruby、さらにJava)は、参照渡しの参照を使用します。明らかにC言語での参照はありませんが、ポインタを使用してそれらを模倣することはできます。これにはいくつかの利点があります。たとえば:C側の参照渡し?

int findChar(char ch, char* in) 
{ 
    int i = 0; 
    for(i = 0; in[i] != '\0'; i++) 
     if(in[i] == ch) 
      return i; 
    return -1; 
} 

これは一般的なCのパラダイムである:(文字が文字列でない場合は、この場合には、-1を返す)、いくつかのエラー値を返すことで、異常または誤った状況をキャッチ。これで

問題がある:あなたがしたい場合はどのような2^31 - 1文字以上の文字列をサポートするために?明らかな解決策はunsigned intを返すことですが、このエラー値では機能しません。私は簡単のため行っていない、しかし、あなたのアイデアを得るいくつかの明白な最適化があります

unsigned int* findChar(char ch, char* in) 
{ 
    unsigned int i = 0; 
    for(i = 0; in[i] != '\0'; i++) 
     if(in[i] == ch) 
     { 
      unsigned int index = (unsigned int*) malloc(sizeof(unsigned int)); 
      *index = i; 
      return index; 
     } 
    return NULL; 
} 

;:

ソリューションは、このようなものですエラー値としてNULLを返します。

すべてのあなたの機能でこれを行う場合は、別の引数を1つの関数の結果を渡すことができるように、あなたはまた、ポインタとしてあなたの引数を渡す必要があります。

私が紛失している(メモリの使用以外にも)このアプローチの欠点はありますか?

EDIT:(それは私の質問によって完全に明白ではない場合)私はC++でのいくつかの経験を持っていることを追加したいが、私はかなりC.

+10

Java *は参照渡しを使用していません。値渡しを使用しますが、参照型の場合、渡される値は参照です。参照と実際のパスの間には大きな違いがあります。 PythonとRubyは同じかもしれません - 私は確信していません。 IMOはここでの用語で非常に正確です。 –

+0

@Jon Skeet:はい、PythonとRubyの値はJavaの参照と同じですが、それらのコミュニティでは用語が異なります – newacct

+0

@Jon Skeet:それはそれを考える方法の1つです。私はそれがJavaを参照渡しであると考える傾向がありますが、プリミティブは例外として同じ言葉で出てきます。それぞれ自分自身に。 :) – Imagist

答えて

6

で完全な初心者です呼び出し元がfreeのインデックスに責任を負うため、悪い考えです。そうでなければ、メモリが漏れています。代わりに、static intを使用して毎回そのアドレスを返すことができます - リークはありませんが、機能はリエントラントではなくなりますが、それは危険です。

は、はるかに良い関数charへのポインタを返すようになり、それが存在しない場合見つけ、またはNULL。それは方法strchr()、BTWの作品です。

は、オリジナルのポストの変更を反映するためにを編集します。

+0

それは私の意図であり、修正されました。 – Imagist

+0

このようなリエントラントではないユーティリティ機能は、起こるのを待っている事故です。私は本当に '静的int'の提案が嫌いです! – Roddy

+0

+1残りは、しかし! – Roddy

1
  1. この関数は、パラメータを逆参照する必要があり、スタックにアクセスするより時間がかかります。
  2. ポインタが初期化されず、予期しない結果が生じることがあります。
  3. 入力のためにあるのポインタを指定する標準的な方法はありませんが、ウィッヒは出力用であり、(そこ拡張、およびネーミングのトリックがありますが、それはまだ問題です)の両方のためです。
2

特定の例では、戻り値の型としてsize_tを使用する必要があります。これは、どのシステムで大きな文字列がどのように取得できるかを適切に表すデータ型です。私。おそらく、size_tが表すことができる文字列よりも長い文字列を持つことはできません。次に、エラー・インジケータとして(size_t)-1をかなり安全に使用することができます。現実的には、実行しているコードのアドレス空間も必要になるため、そのサイズの文字列をメモリに入れることもできません。そのような長い文字列が存在してもサポートされないということは、APIの制限となります。

あなたのアプローチは、メモリを増やすだけでなく、速度が遅くなるという欠点もあります。呼び出し先がmallocする必要があり、呼び出し元を解放する必要があります。それらはかなり高価な操作です。

ここでは、errnoという他の標準的なアプローチがあります。エラーインジケータの場合は、エラーが何であるか分かりません。したがって、Cでは、outパラメーターを使用するのではなく、通常、エラーの詳細をグローバルまたはスレッドローカル変数に入れます。

+0

ありがとうございました。私は 'size_t'を知っていましたが、上のコードは、私が話していることを示すために一緒に投げた例であるため、注意深く考慮しませんでした。 '(size_t)'で 'size_t'の最大値を意味すると仮定した場合、文字列の長さを最大までサポートしたいのですが?これはしばしば心配しないことを理解していますが、私がC言語を使用している理由は、より高いレベルの言語のために通訳を書くことなので、それはまだ懸念しています。 – Imagist

+0

(size_t)-1では、size_tにキャストされた値-1を意味しました。はい、それはあなたにsize_tの最大値を与えます。私が言ったように、あなたは本当にメモリに収まらないので、そのサイズの文字列をサポートする必要はありません。たとえば、32ビットマシンでは、(size_t)-1は4バイトの1バイトの長さです。終了0と一緒に、文字列には4GBが必要です。これにmallocヘッダーを追加すると、アドレススペースに収まりません(コードスペースを必要とするだけでなく、オペレーティングシステムによっては完全な4GBが得られないこともあります)。 –

1

最大の欠点は、findChar()の呼び出し元が返されたメモリを解放()するか、メモリリークを作成することです。あなたはstrchr()ホイールをうまく改造しました。

また、なぜunsigned intへのポインタを返すことが大きな前進だと思っているのかわかりません。まず、unsigned intを返すことができます.2つの31-1-1ではなく、32ビットマシンで2^32までの値を返す機能があれば、それだけです。第二に、大きな文字列の問題を避けることです。さて、もしあなたが64ビットマシンで、「int」と「unsigned int」が32ビットのままであればどうでしょうか?あなたが本当にここで望んでいるものは長いですが、ポインタを返すことは実際にはここでは役に立ちません。

は、malloc関数がなければBOGUS批判

+0

あなたの最後の批判は私には意味がありません。 「NULL」と「&i」の間には、「* i」が「0」に等しいことがわかっています。 – Imagist

+0

申し訳ありませんが、まっすぐ考えることはありません。それは午前2時です、whaddayaが欲しいですか? :) –

+0

あなたのご意見ありがとうございます! – Imagist

3

を省略さ、位置はまだスタック変数ことができ、あなたはif文でそれを使用することができます。

int findChar(char ch, char* in, int* pos) 
{ 
    int i = 0; 
    for(i = 0; in[i] != '\0'; i++) 
    { 
     if(in[i] == ch) 
     { 
      *pos = i; 
      return 1; 
     } 
    } 

    return 0; 
} 
+0

findcharは、 "int findChar(char ch、char * in)"よりはるかに優れたAPIです。戻り値に値とエラーの表示を混在させるのは珍しいことではありませんが、それはKISSの違反であるため、悪い習慣です。 – hlovdal

+0

良いAPIの作成方法については、http://lcsd05.cs.tamu.edu/slides/keynote.pdfおよびhttp://video.google.com/videoplay?docid=-3733345136856180693を参照してください。恐ろしいAPIの例については、Steve McConnellの「Code Complete」のreallocを参照してください。 – hlovdal

1

私は専門家ではないが、私小さなmallocのトンが問題を引き起こす可能性があると考えてください。まず、値を使用した後でメモリを解放する必要があります。その後、空きメモリの断片化にも対処する必要があります。ポインターとして渡すことは、複雑な構造に適しています。

1

私はあなたのコードの最も深刻な欠点は、一般的な失敗と成功した場合の結果の両方を表すために1つの戻り値を使用することです。

これは一般的な習慣ですが、要求事項が変更された場合、説明したようなシナリオが発生する可能性があります。代替の練習は、すなわち、戻り値を分離するために、関数の戻り値は、別途「インデックス」の値から、関数が成功したかどうかがわかります。この

int findChar(char ch, char const * const in, unsigned int * const index) 
{ 
    if (in != NULL && index != NULL) 
    { 
     unsigned int i; 
     for(i = 0; in[i]; i++) 
     { 
      if(in[i] == ch) 
      { 
       *index = i; 
       return EXIT_SUCCESS; 
      } 
     } 
    } 
    return EXIT_FAILURE; 
} 

のようなもの...となります。

また、fortranが指摘したように、ポインタが入力値であるか、出力値であるか、またはその両方(つまり、関数内で変更されたもの)であるかを強制する方法はありません。