1

私は次の基準に従うことになっています:

関数answer4(ポインターパラメーターとn)を実装します。

  1. malloc()n個のアイテム を使用してstudent_recordの配列を準備します。

  2. 学生レコードをパラメータから配列にn回複製します。

  3. 配列を返します。

そして、私は以下のコードを持ってきましたが、それは明らかに正しくありません。これを実装する正しい方法は何ですか?

student_record *answer4(student_record* p, unsigned int n)
{
    int i;
    student_record* q = malloc(sizeof(student_record)*n);
    for(i = 0; i < n ; i++){
        q[i] = p[i];
    }
    free(q);
    return q;
};
4

8 に答える 8

1

この質問のコードは非常に急速に進化していますが、この回答の時点では、次の2行が含まれています。

free(q);
return q;

これは間違いであることが保証されています-free引数の呼び出しが無効なメモリを指していると、その後、の値を使用すると何かが発生する可能性がありqます。つまり、無効なポインタを返しています。戻ってきたのでq、まだ解放しないでください!これは「呼び出し元が所有する」変数になり、それを解放するのは呼び出し元の責任になります。

于 2012-04-27T15:25:33.000 に答える
1

a[]ローカル自動配列です。関数から戻ると、メモリから消去されるため、呼び出し元の関数は、返された配列を使用できません。

おそらくやりたかったのはmalloc、新しい配列(つまり、ではないp)を作成することです。この配列に複製を割り当て、その値を返して、mallocedメモリを解放する必要があります。

于 2012-04-27T15:03:36.210 に答える
1

より適切な名前を使用してみてください。コードにある明らかな取り違えエラーを回避するのに役立つ場合があります。

たとえば、次のコマンドで関数を開始します。

student_record * answer4(const student_record *template, size_t n)
{
...
}

また、コードがより明確になります。const最初の引数が入力専用であることを明確にするために追加しsize_t、「カウント」と物のサイズを処理するときに適した2番目の引数のタイプを作成したことに注意してください。

于 2012-04-27T15:03:56.087 に答える
1
p = malloc(sizeof(student_record)*n);

これには問題があります。p入力引数を上書きしているため、その行の後に渡されたデータを参照できません。

これは、内側のループが初期化されたデータを読み取ることを意味します。

これ:

return a; 

これも問題です - ローカル変数へのポインタを返しますが、これは良くありません - そのポインタは関数が戻るとすぐに無効になります。

必要なものは次のようなものです:

student_record* ret = malloc(...);

for (int i=...) {
 // copy p[i] to ret[i]
}

return ret;
于 2012-04-27T15:02:04.843 に答える
1

1) を呼び出して、コピーするはずだった配列 p を再割り当てしましたmalloc()

2) ローカルスタック変数のアドレスを返すことはできません(a)。a をポインターに変更し、それを p のサイズに malloc し、p をコピーします。malloc されたメモリはヒープメモリであるため、そのようなアドレスを返すことができます。

于 2012-04-27T15:02:46.573 に答える
0

これはコンパイルされ、私が思うに、あなたが望むことをします:

student_record *answer4(const student_record *const p, const unsigned int n)
{
    unsigned int i;
    student_record *const a = malloc(sizeof(student_record)*n);
    for(i = 0; i < n; ++i)
    {
        a[i] = p[i];
    }
    return a;
};

いくつかのポイント:

  1. 既存のアレイはとして識別されpます。あなたはそれからコピーしたいです。あなたはおそらくそれを解放したくないでしょう(解放することはおそらく発信者の仕事です)。
  2. 新しい配列はaです。あなたはそれにコピーしたいです。呼び出し元が必要とするため、関数はそれを解放できません。したがって、呼び出し元は、呼び出し元がそれを実行した後、それを解放する責任を負う必要があります。
  3. 配列にはn、0からn-1までのインデックスが付けられた要素があります。したがって、インデックスの上限を表す通常の方法はですi < n
  4. 私が追加したconstsは必須ではありませんが、よく書かれたコードにはおそらくそれらが含まれています。
于 2012-04-27T15:13:03.570 に答える
0
student_record* answer4(student_record* p, unsigned int n)
{
    uint8_t *data, *pos;
    size_t size = sizeof(student_record);
    data = malloc(size*n);

    pos = data;
    for(unsigned int i = 0; i < n ; i++, pos=&pos[size])
        memcpy(pos,p,size);

    return (student_record *)data;
};

あなたはこのようにするかもしれません。

于 2012-04-27T15:10:23.780 に答える
0

とはいえ、この質問には以前に良い回答がありましたが、自分で追加することは避けられませんでした。Collegue でパスカル プログラミングを学んだので、C 関連のプログラミング言語でこれを行うのに慣れています。

void* AnyFunction(int AnyParameter)
{
   void* Result = NULL;

   DoSomethingWith(Result);

   return Result;
}

これにより、デバッグが容易になり、ポインターに関連する @ysap による言及のようなバグを回避できます。

覚えておくべき重要なことは、単一のポインターを返すという質問の言及です。これは、ポインターを使用して単一のアイテムまたは連続した配列をアドレス指定できるため、これは一般的な警告です!!!

This questionは、ARRAY SYNTAXを使用せずに、ポインターを使用して配列をコンセプトとして使用することを提案しています。

// returns a single pointer to an array:
student_record* answer4(student_record* student, unsigned int n)
{
  // empty result variable for this function:
  student_record* Result = NULL;

  // the result will allocate a conceptual array, even if it is a single pointer:
  student_record* Result = malloc(sizeof(student_record)*n);

  // a copy of the destination result, will move for each item
  student_record* dest = Result;

  int i;
  for(i = 0; i < n ; i++){
    // copy contents, not address:
    *dest = *student;

    // move to next item of "Result"
    dest++;
  }

  // the data referenced by "Result", was changed using "dest"
  return Result;
} // student_record* answer4(...)

ポインタによるアドレス指定のため、ここに添字演算子がないことを確認してください。

Pascal と C フレームの戦争を始めないでください。これは単なる提案です。

于 2012-04-27T15:36:34.983 に答える