3

要するに、私はこれをしたいと思います:

const char **stringPtr = &getString();

ただし、右辺値に & を使用できないことは理解しています。だから私はこれにこだわっています:

const char *string = getString();
const char **stringPtr = &string;

2行で生活できます。このハックで問題が発生していますか? stringPtr宣言されている関数から抜け出すことを恐れる必要はありませんよね?

編集: もともと完全なコンテキストを含めていなかったことをお詫びします。私は、グラフィックに OpenGL を使用して C でゼロからビデオ ゲームを構築するという夏のプロジェクトを引き受けました。libconfigを使用して、テキスト ファイルから構成データを読み取っています。

構成ファイルから特定の文字列を見つけるための便利な関数の 1 つは、次のようになります。

int config_setting_lookup_string(const config_setting_t *setting,
                                 const char *name, const char **value)
{
  config_setting_t *member = config_setting_get_member(setting, name);
  if(! member)
    return(CONFIG_FALSE);

  if(config_setting_type(member) != CONFIG_TYPE_STRING)
    return(CONFIG_FALSE);


  *value = config_setting_get_string(member);
  return(CONFIG_TRUE);
}

その値が割り当てられる方法は、関数valueに uninitialized を指定すると、未定義のガベージを逆参照しようとすることを意味します。これにより、ほとんどの場合、segfault が発生します。この問題に対する私の現在の回避策はvalue、次のように、最初に別のポインターに初期化することです。

const char *dummyPtr;
const char **fileName = &dummyPtr;
config_setting_lookup_string(foo, "bar", fileName);

そのため、この 2 段階の初期化を実行する必要がないように、関数の最後の部分を書き直す最善の方法を見つけようとしています。変更された関数は次のようになると考えていました。

int config_setting_lookup_string(const config_setting_t *setting,
                                 const char *name, const char **value)
{
  config_setting_t *member = config_setting_get_member(setting, name);
  if(! member)
    return(CONFIG_FALSE);

  if(config_setting_type(member) != CONFIG_TYPE_STRING)
    return(CONFIG_FALSE);

  const char *string = config_setting_get_string(member);
  value = &string;
  return(CONFIG_TRUE);
}
4

7 に答える 7

3

を必要とする関数を呼び出す場合は、次のconst char**ようにすることができます。

const char *s = getString();
myFunction(&s);

上記sの例では がスタックに割り当てられているため、関数から a を返したい場合はconst char**、代わりにヒープに配置する必要があります。

const char **sp = malloc(sizeof(const char *));
*sp = getString();
return sp;

HTH

于 2010-05-09T04:53:53.833 に答える
1

いいえ、あなたがconfig_setting_lookup_string()説明した方法で変更することはできません。変数へのポインターを返していますが、stringその関数が終了するとすぐに、その変数はスコープ外になり、破棄されます。

ただし、最初の問題は非常に簡単に修正できます。の定義はそのままにして、次のconfig_setting_lookup_string()ように呼び出します。

const char *fileName = NULL;
config_setting_lookup_string(foo, "bar", &fileName);
于 2010-05-09T06:55:56.373 に答える
1

stringあなたの場合はローカルなので、ローカルのメモリはメソッドを離れるときに他の目的に再利用できる(そしておそらく再利用される)ため、そのアドレスを取得することは悪い考えです。一般に、スコープ外のローカル変数のアドレスを使用することはお勧めできません。

何を達成しようとしていますか?

于 2010-05-09T04:31:49.337 に答える
0

2行必要です。ただし、string はスタック上のローカル変数であるため、スコープ外になると、getString() によって返されるデータへのポインターがなくなる場合があります。

于 2010-05-09T04:29:28.967 に答える
0

を返す場合stringPtrは、ローカル変数 ( string) へのポインターを返します。いいえ、それはできません。

なぜこれをやろうとしているのですか?そうすることで、より良い提案ができるかもしれません。

更新: わかりました。あなたが何をしようとしているのかわかりました。あなたは間違っています:

value = &string;

が出力パラメーターとして意図されている場合、ローカル変数に代入してvalueいるため、上記の行は機能しません。

余分なレベルの間接化に混乱させないでください。type の出力パラメーターを持つ関数を作成する場合、次のようにT記述します。

void foo(T* value)
{
    *value = GetT();
}

に置き換えTますconst char*

...
*value = string;
...

これで、一時的なローカル変数は使用されなくなりました。もちろん、これが最初のコードの書き方でした (そして、その部分は正しかった) ため、実際には役に立ちません。あなたの意図に対処するには、次のことを行う必要があります。

  1. config_setting_lookup_stringしなさいassert(value != NULL)
  2. 関数の呼び出し元を監査し、ガベージを渡さないように修正します。彼らはやるべきです:

    const char* foo; config_setting_lookup_string(..., &foo);

ではない:

const char** foo;
config_setting_lookup_string(..., foo);
于 2010-05-09T04:29:56.273 に答える
0

私はノルナゴンとカフェのソリューションが好きです。

const char *fileName;
config_setting_lookup_string(foo, "bar", &fileName);

ただし、変更できる場合config_setting_lookup_stringは、次の方法でも変更できます。

int config_setting_lookup_string(..., const char *&value)
{
  ...
  const char *string = config_setting_get_string(member);
  value = string;
  ...
}

const char *fileName;
config_setting_lookup_string(foo, "bar", fileName);
于 2010-05-09T07:08:12.167 に答える
0

追加された情報から、あなたがしようとしているのは、関数の引数の 1 つを介して文字列を返したい関数を呼び出すことのようです。私の意見では、これを行う最良の方法は次のようになります。

const char* fileName;
config_setting_lookup_string(..., &fileName);
(...)
return fileName;

これにより、スタックに const char* 用のスペースが割り当てられます。関数呼び出しは、ポインターを返したい文字列のアドレスで埋めます。このポインター値は、必要に応じて関数から渡すことができます (スタックを指すポインターへのポインターとは異なり、関数が戻ると無効になります)。「getString()」で fileName を初期化すると、返された文字列へのポインタが上書きされ、文字列の割り当てが解除されないため、おそらくメモリ リークが発生することに注意してください。

于 2010-05-09T07:32:05.467 に答える