1

コードのほぼすべての部分で、ローカル ポインターを初期化する次の方法を確認します。そうすることの理由と複雑さを理解したい。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void initialize_p(char **p)
{
        char *p_local = NULL;
        p_local=malloc(6);
        strcpy(p_local,"sandy");
        *p = p_local;
}
int main(void)
{
        char *p = NULL;
        initialize_p(&p);
        printf("Name : %s\n",p);
        return 0;
}

それだけです、ここでは単純な文字列で示しています。そして、私の実際のコードでは、構造体を使用して行われています。

私は上記のロジックを理解していますが、理解していません。上記の実装スタイルに含まれる概念をクリアしてください。また、他に良い方法があれば教えてください。

啓発してください.. :)

4

5 に答える 5

4

おそらく、ポインターへのポインターを引数として渡すのではなく、新しく割り当てられた文字列を返すでしょう。

char *initialize(void) {
    char *init = "sandy"; 
    char *ret = malloc(sizeof(init)+1);
    if (ret != NULL)
        strcpy(ret, init);
    return ret;
}

int main() {
    char *p = initialize();
    printf("Name: %s\n", p);
    free(p);
    return 0;
}
于 2012-08-16T04:48:30.323 に答える
0

それはアウトパラメータです。この関数は結果を生成し、渡したパラメーターに保存します。これは、結果のサイズが異なる可能性がある場合、またはパラメーターのタイプが不透明である場合によく使用されます。

個人的には、結果を返す方がはるかに明確であり、動的割り当てが必要な場合にエラーが発生しにくいと思います(JerryCoffinの回答+1に見られるように)。

動的割り当てが不要な場合、それが自明に小さくない場合は、参照によって(非定数パラメーターとして)渡します。

struct t_struct { int a[100]; };

void InitStruct(struct t_struct* pStruct) {
  pStruct->a[0] = 11;
  ...
}

struct t_struct s;
void InitStruct(&s);

自明に小さい場合は、値で返すことを検討してください。

于 2012-08-16T04:53:46.160 に答える
0

initialize_pでは、メモリのチャンクが割り当てられ、一部の文字列がメモリにコピーされます。初期化子の呼び出し元がこの新しいメモリチャンクのアドレスを取得するために、ポインタpのアドレスがinitialize_pに渡されます。

    char **p

         +---+---+---+---+---+----+
   *p -> | s | a | n | d | y | \0 |
         +---+---+---+---+---+----+

* pのみが渡された場合、関数内にポインターを設定することは、次と同等になります。

void foo(int a)
{
  a=3;
  ...
}

より良い方法は、関数で行うのと同じことを行うstrdupを使用することです。

char* initialize_p()
{
   return strdup("sandy");
}

また、メモリリークを回避するために、返された文字列を解放してください。

于 2012-08-16T04:53:59.797 に答える
0

割り当てと割り当て解除の関数ペアを作成することをお勧めします

char *createP()
{
    char *p = NULL;
    p=malloc(6);
    strcpy(p,"sandy");
    return p;
}
void freeP(char *p)
{
    if (p) free(p);
}
int main(void)
{
    char *p = createP();
    printf("Name : %s\n",p);
    freeP(p);
    return 0;
}
于 2012-08-16T04:57:12.717 に答える
0

コンセプトをクリアしますか?まあ、そのような単純なケースでは、byref出力パラメーターを操作する意味がわかりません-私にとって、オブジェクト指向のような構造コンストラクター関数は、次のように機能する場合に理解しやすくなります:

struct foo *bar = myobj_new(); // uses malloc and returns a pointer
// do something with bar
myobj_destroy(bar); // uses free

関数の戻り値をエラー/成功コードとして使用できるため(SQLite3を見たことがありますか?)、この設計が優れていることに同意する人もいますが、私は同意しません。関数の最も重要な主要な結果は、補助的なものではなく、戻り値を通過する必要があると思います。(私は、NULLを返し、バイパスされたエラーコードを設定することによって失敗が示されるライブラリを作成する傾向があります)。

私が考えることができる唯一の有効なシナリオは、このような引数を渡すことがより論理的または対称的である場合です。たとえば、C stdlib関数qsort()に似ているが、必要に応じて2つの要素を交換するには、その比較関数自体が必要な、非常に奇妙なソート関数を想像してみてください。比較関数は、それらを交換するために2つのパラメーターへのbyrefアクセスを明らかに必要としますが、アルゴリズムを最適化するために、最初に検出された順序を呼び出し元の並べ替え関数に返すことも役立つ場合があります。したがって、この比較関数は次のようになります。

int compare(void *a, void *b)
{
    int x = *(int *)a;
    int y = *(int *)b;

    if (x > y)
    {
        *(int *)a = y;
        *(int *)b = x;
        return +1;
    } else if (x < x) {
        return -1;
    }

    return 0;
}

まあ、ほとんどそれは私の意見についてです...

于 2012-08-16T04:58:27.430 に答える