0

プログラミングの演習と同じようにmemmoveを実装しようとしていましたが、mallocを使用しようとすると、memmove関数でメモリアクセス違反が発生します。関数は次のとおりです。

//Start

void* MYmemmove (void* destination, const void* source, size_t num) { 

    int* midbuf = (int *) malloc(num); // This is where the access violation happens.
    int* refdes = (int *) destination; // A pointer to destination, except it is casted to int*
    int* refsrc = (int *) source; // Same, except with source
    for (int i = 0;num >= i;i++) { 
        midbuf[i] = *(refsrc + i); // Copy source to midbuf
    }
    for (int i = 0;num >= i;i++) { 
        refdes[i] = *(midbuf + i); // Copy midbuf to destination
    } 
    free(midbuf); // free midbuf 
    refdes = NULL; // Make refdes not point to destination anymore
    refsrc = NULL; // Make refsrc not point to source anymore
    return destination;
}

ちなみに、私はポインタの初心者なので、間違いがあっても驚かないでください。私は何が間違っているのですか?

4

7 に答える 7

4

他の提案には注意してください!答えは、memmoveがどのように使用されるかによって異なります。他の回答では、intのサイズを考慮してmalloc呼び出しを変更する必要があると述べています。ただし、me​​mmove関数を使用して「このバイト数を移動する」ことを意味する場合、実装は正しくありません。代わりに、char *を使用して、一度にいくつかの問題を処理します。

また、anintは通常4バイトで、char通常は1バイトです。受信するvoid*アドレスがワードアラインされていない(4バイトの倍数ではない)場合、問題が発生します。ワードアラインされていないintをコピーするには、複数の読み取りと高価なビットマスキングを行う必要があります。これは非効率的です。

最後に、メモリアクセス違反が発生したのは、midbufintポインターを毎回インクリメントし、一度に4バイトずつ進めていたためです。ただし、割り当てられたのはnumバイトのみであるため、最終的には割り当てられた領域の終わりを超えてアクセスしようとします。

/** Moves num bytes(!) from source to destination */
void* MYmemmove (void* destination, const void* source, size_t num) { 

    // transfer buffer to account for memory aliasing
    // http://en.wikipedia.org/wiki/Aliasing_%28computing%29
    char * midbuf = (char *) malloc(num); // malloc allocates in bytes(!)
    char * refdes = (char *) destination;
    char * refsrc = (char *) source;

    for (int i = 0; i < num; i++) { 
        midbuf[i] = *(refsrc + i); // Copy source to midbuf
    }

    for (int i = 0; i < num; i++) { 
        refdes[i] = *(midbuf + i); // Copy midbuf to destination
    } 

    free(midbuf); // free midbuf
    // no need to set the pointers to NULL here.
    return destination;
}

バイトごとにコピーすることで、アライメントの問題や、num自体が4バイトの倍数にならない場合(たとえば3、intが大きすぎてその移動ができない場合)を回避できます。

于 2012-10-07T18:01:56.753 に答える
3

文字列をmallocに置き換えます。

int* midbuf = (int *) malloc(num*sizeof(int)); 

num問題は、intの要素ではなくnumbytesを割り当てたことです。

于 2012-10-07T17:54:05.703 に答える
1
int* midbuf = (int *) malloc(num); // This is where the access violation happens.
int* refdes = (int *) destination; // A pointer to destination, except it is casted to int*
int* refsrc = (int *) source; // Same, except with source
for (int i = 0;num >= i;i++) { 
    midbuf[i] = *(refsrc + i); // Copy source to midbuf
}

mallocバイトのみですnumが、ループでは、num intsをコピーしようとします。int通常は1バイト以上かかるため、範囲外にアクセスしています。

于 2012-10-07T17:54:26.490 に答える
0

注目すべき2つの問題があります

1.メモリスペース

(質問が示唆MYmemmoveするように移動するカスタム実装を行う場合)ints

    int* midbuf = (int *) malloc(num * sizeof(int));

mallocバイトベースであり、numバイトを割り当てます。int *へのポインタintsです。意味midbuf[x]はからメモリにアクセスしますmidbuf + sizeof(int)*x代わりにnum を割り当てintsます(intのサイズはアーキテクチャによって異なります。通常は4バイトまたは2バイトです)。したがって、malloc(num * sizeof(int))

2.配列インデックス

    for (int i = 0;num > i;i++) { 

C(およびC ++)では、配列は0ベースです。つまり、最初のインデックスは0です。あなたはそれを正しくしました。ただし、num intsを予約すると、使用可能なインデックスはfromから0になりnum-1ます。ループでは、条件のおかげで、がからにi変化します。つまり、アイテムにアクセスします。したがって、(または)がより良い条件になります。0numnum >= inum+1num > ii < numfor

于 2012-10-07T18:06:33.897 に答える
0

メモリアクセス違反?

アクセスする資格のないメモリにアクセスしようとしています。nullポインターがあるか、ポインターが別のプログラムまたはコードセグメントを指している可能性があります。

于 2012-10-07T17:54:04.523 に答える
0

問題は、numバイトをにマロッキングしてから、 intをmidbufコピーしていることです。numほとんどのプラットフォームではanintがバイトよりも大きいため、問題が発生します。に変更すれmallocnum*sizeof(int)、その問題は発生しません。

于 2012-10-07T17:55:00.933 に答える
-1
#include <stdlib.h>  // did you included this?


void* MYmemmove (void* destination, const void* source, size_t num) { 

    char *Source = source, *Destination = destination;
    char *Middle = malloc( sizeof(char) * num );    // midbuf

    for (int i = 0; i < num ; i++) { 
        Middle[i] = Destination[i]; // Copy source to midbuf
    }
    for (int i = 0; i < num ; i++) { 
        Destination[i] = Middle[i]; // Copy midbuf to destination
    }

    free(Middle);                   // free memory allocated previously with malloc
    return destination;
}

mallocに必要なライブラリが含まれていなかったため、アクセス違反が発生する可能性があります(関数定義を忘れた場合でも、標準のcはエラーをスローしません)。Cにはガベージコレクションがないため、ポインタをNULLとしてマークする必要はありません(ポインタは-ポインタです。メモリ自体ではなく、メモリ内のポイントへのアドレスです)。

次のようなポインタについて考えてください

ポインタのアドレス0x12430x4221宛先->{ある種のデータ}

Destination = 0x1243 *Destination=現在アドレス0x4221にある値

voidポインタにインデックスを付けることもできません。最初にそれらを何らかのタイプにキャストする必要があります。これにより、コンパイラーはそれらが必要とするオフセットの量を認識します。

Destination [x] = *(Destination + x)

charは1バイトであるため、charポインターは実際にはxバイト移動しますが、intは4バイトであり、intポインターは4*xバイト移動します。技術的に聞こえてもあまり心配しないでください。本当に低いレベルに到達するときに重要になります;)

于 2012-10-07T18:01:53.697 に答える