3

ここにプロトタイプがあります:

void *memset(void *s, int c, size_t n)

たとえば、memsetを使用するときに何かを返す必要があるかどうかはわかりません

memset(str, 'a', 5);

それ以外の

str = memset(str, 'a', 5);

ここに私のコードがあります:

void *my_memset(void *b, int c, int len)
{
    int i;

    i = 0;
    while(b && len > 0)
    {
        b = c;
        b++;
        len--;
    }
    return(b);
}

int main()
{
    char *str;

    str = strdup("hello");
    my_memset(str, 'a', 5);
    printf("%s\n", str);
}

ポインターとメモリをよりよく理解するために、この関数で配列を使用したくないので、2つのことを取得しません。 「\0」文字の前で停止します

編集:キャストせずにこの機能を実行する方法はあるのだろうかと思っていましたか?

4

6 に答える 6

10

int c を void b ポインターの文字にコピーする方法

void ポインターを unsigned char ポインターに変換します。

void  *my_memset(void *b, int c, int len)
{
  int           i;
  unsigned char *p = b;
  i = 0;
  while(len > 0)
    {
      *p = c;
      p++;
      len--;
    }
  return(b);
}

「\0」文字の前で確実に停止するために、while で使用する条件

memset は、渡された長さを信頼する必要があります。memset は、0 で終了する文字列だけでなく、メモリの一般的な部分で動作する必要があるため、そのようなチェックは必要ありません。

とにかく0バイトをチェックする必要がある場合。あなたがするだろう

if (*p == 0) //or if(!*p )
     break;
于 2013-09-17T13:56:42.850 に答える
2

関数がしばしば値を返す理由は、呼び出し元の関数にエラー状態を返すためです。メモリ関連の関数では、通常、結果があるべき場所 (NULL を含む) と同じポインターです。あなたの例では、my_memset関数の戻り値を使用したくないかもしれませんが、通常はコード評価に含めることができるためです (これに適した言葉が思いつきません)。

if(!my_memset((void *)str, 'a', 5))
{
    printf("An error occurred in my_memset()\n");
}

またはマクロで、たとえば、コピーしたメモリの末尾へのポインターを返すにはchar

#define INIT_MEM_PTR_END(a,x) (my_memset((void *)&(a), (x), sizeof(a)) + sizeof(a))

これはおそらく良い例ではありません (さらにaが既にポインターである場合の潜在的な問題など)。 .

また、ポインターを逆参照する前にポインターを確認する必要があります。たとえばvoid *bNULL の場合、セグメンテーション違反が発生します。

void *関数の意図が特定のデータ型へのポインターを渡すときほど明確ではない可能性があるという事実を除いて、を渡すことに問題はありません。内部でも有効なものにキャストしてください。また、このように、関数を使用して、任意のメモリを特定の 16 進数値 (char を介して) またはすべて 0 に非常に簡単に設定することができます。

この場合b、コピーしようとしている値と同じ型にキャストする必要があるように思われintます。ただし、引数が不明になります。サイズはバイトですか、それともポインタにコピーするlen回数ですか?cb

あなたはそのメモリ位置にmain()a をコピーしているので、あなたを a に変更し、あなたをaにキャストし、長さをバイト単位またはコピーする回数にする方が良いでしょう。曖昧さを避ける。charccharbchar*lenc*b

あなたが書いた方法では、指定された回数、またはnull文字に出会うまで、最短/最短cの回数をコピーします。lenそれがあなたの意図なら、それは結構です。

void *my_memset(void *b, char c, int len)
{
    char *b_char = (char *)b;

    if (b == NULL) return NULL;

    while(*b_char && len > 0)
    {
        *b_char = c;
        b_char++;
        len--;
    }

    return b; //as this pointer has not changed
}

int main()
{
    char *str;

    str = strdup("hello");
    if (!my_memset((void *)str, 'a', 5))
    {
        printf("An error occurred in my_memset()\n");
    }
    else
    {
        printf("%s\n", str);
    }
}
于 2013-09-17T15:01:33.390 に答える
2

ポインター演算は、ポインターが指す型のサイズによってポインターをオフセットすることに基づいています。そのポインターのインクリメントを開始する前に、void*ポインターをchar/へのポインターに変換する必要がありunsigned charます。

void* my_memset(void *s, int c, size_t len) {
    unsigned char *dst = s;
    while (len > 0) {
        *dst = (unsigned char) c;
        dst++;
        len--;
    }
    return s;
}

また、メモリ領域 s へのポインターを返すことに注意してください。そのため、元のポインターを返す必要があります (インクリメントを開始する前に)。memset

于 2013-09-17T14:02:21.920 に答える
1
void   *my_memset(void *b, int c, int len)
{
  if (b == NULL || len <= 0)
      return b;
  unsigned char *ptr = b;
   while(*ptr != '\0' && len--)
    {
      *ptr++ = (unsigned char)c;
    }
  return(b);
}
于 2013-09-17T14:01:52.903 に答える
0

ダフ デバイスを使用して、さらに優れたパフォーマンスを得ることができます。

#define DUFF_DEVICE_8(aCount, aAction) \
do { \
int count_ = (aCount); \
int times_ = (count_ + 7) >> 3; \
switch (count_ & 7){ \
case 0: do { aAction; \
case 7: aAction; \
case 6: aAction; \
case 5: aAction; \
case 4: aAction; \
case 3: aAction; \
case 2: aAction; \
case 1: aAction; \
} while (--times_ > 0); \
} \
} while (0)
于 2013-12-20T17:14:38.180 に答える