1

メイン関数に配列を渡し、メイン関数からintを渡す関数があります。この新しい関数内の配列に対して操作を行っています。これをfooと呼びましょう。fooでは、52個のセルですべて0の別の配列を初期化します。メインから渡した配列に対して操作を行い、そのデータを新しく初期化された配列に転送します。新しい配列をメイン関数に戻したい。しかしもちろん、配列のようなデータ構造を返すことはできません。したがって、代わりに、この配列を指すintポインターを返します。int main内で、配列内のさまざまなセルを指すようにポインターを渡します。ポインターが指しているものの結果を出力するとき、それは0または0より大きい整数を指しているはずです。しかし、代わりに、一貫性のない結果が得られます。何らかの理由で、0である必要がある値の一部は、ガベージデータを出力します。私' しばらくの間バグを見つけようとしてきましたが、私はそれを中古で見たかっただけです。とにかく、この部分のコードの一般的なアイデアは次のとおりです...

int main(){
    int *retPtr;
    char input[] = "abaecedg";
    retPtr = foo(input, size);
    for(i=0; i<52; i++){
        // error displayed here
        printf("%d\n", *(retPr + i));
    }
}

int foo(char input[], int size)
{
    int arr[52] = {0};      // should initialize all 52 cells with 0.
    int i=0, value;         // looking for non-zero results in the end.        
    int *ptr = &arr[0];                        
    for(i=0; i<size; i++){
        if(arr[i] > 64 && arr[i] < 91){
            value = input[i] - 65;
            arr[value]++;
        }
    }
    return ptr;
}

うまくいけば、これは私がやろうとしていることを理解するでしょう。foo関数で、特定のアルファベットの頻度を見つけようとしています。これは少しわかりにくいかもしれませんが、コードにはコメントやすべてが含まれているため、できるだけ簡潔にしたいと思いました。一部の値(数値> 0、0)と他の値のガベージ値を取得する理由はありますか?

4

2 に答える 2

6

ガベージが返される理由は、で作成された配列がfoofoosスタックフレームに割り当てられ、そのフレームにポインタを返すためです。そのフレームは、戻るときに破棄されfooます。

戻り後に配列を残したい場合は、(mallocとfriendsを使用して)ヒープに配列を割り当てる必要がありfooます。free()アレイを使い終わったら、それを忘れないでください。

int main(){
    char input[] = "abaecedg";
    int retPtr[] = foo(input, size); //An array and a pointer is the same thing
    ...
    free(retPtr);
}

int *foo(char input[], int size)
{
    int arr[] = calloc(52*sizeof(int); // should initialize all 52 cells with 0.
    ...
    arr[value]++;
    ...
    return arr;
}

もう1つの方法は、次のようfooに、配列をパラメーターとして受け取り、それを操作することです。

int main(){
    int ret[52] = {0};
    ...
    foo(input, size, ret);
    ...
}

void foo(char input[], int size, int *arr)
{
    ...
    arr[value]++;
    ...
    return; //Don't return anything, you have changed the array in-place
}

これが機能する理由は、配列がポインタとまったく同じものであるためです。したがって、実際には、参照によって配列をに渡しますfoo。のスタックフレーム内で、arrと同じ場所を指します。retmain

于 2012-12-02T07:27:00.697 に答える
1

関数fooでは、配列arrはローカル配列です。つまり、スタックに割り当てられます。関数から戻った後にスタックが巻き戻され、その内容が保証されなくなるため、スタックに割り当てられたデータのポインターを返さないでください。

配列を返したい場合はmalloc、たとえば、を使用してヒープに割り当て、返されたポインタを返す必要がありますmalloc。しかし、その後free、プログラムのどこかでそのメモリを使用する必要があります。解放に失敗すると、「メモリリーク」と呼ばれるものが発生します。これは、環境に応じて、このプログラムの再実行をクラッシュまたは妨害する場合としない場合があります。きれいではない状況、それは確かです。

そのため、Cは、関数から物を返すなどの関数型プログラミングのイディオムにはあまり適していないと思います(プリミティブ型でない限り)。別の配列をfoo(サイズ変数を伴う出力配列)に渡し、その配列を埋めることで、あなたがやろうとしたことを達成します。

または、配列を構造体内でラップして、その構造体を返すこともできます。構造体は値で返すことができます。その場合、構造体はスタックを介して呼び出し元の関数の戻り値にコピーされます。

于 2012-12-02T07:35:24.227 に答える