【问题标题】:Problems writing the memset function编写 memset 函数的问题
【发布时间】:2009-12-14 00:34:45
【问题描述】:

我正在编写memset 函数,我的代码如下,我遇到了问题

void* memsetFun(void* pointer, int c, int size) {

  if ( pointer != NULL && size > 0 ) {

    unsigned char* pChar =  pointer;


    int i = 0;

      for ( i = 0; i < size; ++i) {

      unsigned char temp = (unsigned char) c;

      *pChar++ = temp; // or pChar[i] = temp (they both don't work)

    }
  }  
    return pointer;


}

我也尝试了 pChar[i] = 我们想要的值,但仍然无法正常工作。它给了我一些没有任何意义的垃圾号码。

我叫它:

memsetFun(address, num, size);
printf("value at %p is %d\n", address, *((int*) address));

我在哪里调用地址(我只是输入地址)

例如,如果您打印字符 ( c ),它会打印出一个奇怪的字符,看起来像 (对于值 4 )

0 0
0 4

【问题讨论】:

  • 你确定调用者的大小不是零吗?
  • 什么是p?我猜你的意思是pointer
  • 为什么您的原型与 ANSI C 的 memset 不同?您应该使用size_t 作为第三个参数。另外,请发布实际代码(复制粘贴),不要在这里输入。什么是“p”?最后,发布显示错误的最少代码。
  • 是的 p 是指针,我把它当作指针其实很抱歉 :)
  • 你能给我们展示一个显示错误的完整程序吗? num 是什么,size 是什么?你期望输出是什么?我认为你的功能是正确的,但你对它应该做什么有错误的想法。

标签: c


【解决方案1】:

您的代码对我来说看起来不错,这里有几个人评论说它可以在他们的系统上运行。

因此,显而易见的事情就是对其进行调试 - 这是一项将来会派上用场的技能 :-) 您应该现在就学习它

下面的代码运行时会输出什么?

void* memsetFun(void* pointer, int c, int size) {
    printf("A %x %d %d\n", pointer, c, size);
    if ( pointer != NULL && size > 0 ) {
        printf("B\n");
        unsigned char* pChar =  pointer;
        int i = 0;
        for ( i = 0; i < size; ++i) {
            printf("C %d (%d)", i, *pChar);
            unsigned char temp = (unsigned char) c;
            *pChar++ = temp; // or pChar[i] = temp (they both don't work)
            printf(" -> (%d)", i, *(pChar-1));
        }
    }  
    printf("D\n");
    return pointer;
}

从输出中,应该清楚代码所走的路径以及您的参数是什么(这将极大地帮助调试过程)。

更新:

如果你用零以外的任何东西填充你的内存块并使用这个:

printf("value at %p is %d\n", address, *((int*) address));

打印出来,你得到奇怪的结果。

您基本上要求将这些字节中的一些解释为整数。因此,例如,如果你用0x02 字节填充它并且你有一个 4 字节整数类型,你会得到整数 0x02020202 (33686018),不是 0x02 你可能预计。如果您想查看第一个 character 值是什么,请使用:

printf("value at %p is %d\n", address, *((char*) address));

根据您的最新问题更新:

例如,如果您打印字符 ( c ),它会打印出一个奇怪的字符,看起来像 (对于值 4 )
0 0
0 4

如果这是单个字符并且您将其作为字符打印,则可能根本没有任何问题。许多输出流会为您提供控制字符(在本例中为 CTRL-D,ASCII 代码 4)。如果你用 ASCII 码 0x30 (48) 填充它,你会看到字符 '0' 或 ASCII 0x41 (65) 会给你'A'。

【讨论】:

  • 我改变了它,但它仍然给我同样的错误(是的,当它应该是 2 时它给了我值 33686018,但即使在将该代码更改为您的代码之后:()跨度>
  • 33686018 为 0x02020202,即 2 重复 4 次。一切都很好,除了你对记忆的理解。 :-)
  • 感谢 Alok :) 这就是我试图了解更多信息的原因。无论如何,我知道 33686018 是 0x02020202 但问题是我得到它的原因。
  • @unknown,看看这个答案的部分,紧跟在“更新:”之后。您有一个内存块,其中每个字符都是 0x02,但您正在从该内存块打印一个整数。在您的情况下,整数是 4 个字符,not 一个。这就是为什么你得到值 0x02020202。如果你从那个块打印一个 char,你会得到你期望的值。
  • memset 每个字节只能设置一个值。因此,给定 0x02,它会在所有字节上设置该值。稍后,您将这些字节中的 4 个解释int,并打印出来。如果您解释其中 2 个字节,您将得到 514 作为输出。所以,你的解释是错误的。另外,查看我对您的问题的回答:它不仅为这个问题提供了有用的信息,还为您将来想问的所有问题提供了有用的信息。谢谢!
【解决方案2】:

正如已经指出的那样,您的函数可以正常工作。这是一个完整的例子:

#include <assert.h>
#include <string.h>

void* memsetFun(void* pointer, int c, int size) {
    if ( pointer != NULL && size > 0 ) {
        unsigned char* pChar =  pointer;
        int i = 0;
        for ( i = 0; i < size; ++i) {
            unsigned char temp = (unsigned char) c;
            *pChar++ = temp; // or pChar[i] = temp (they both don't work)
        }
    }
    return pointer;
}

int main() {
    // Your memset
    char a[10];
    memsetFun(a, 'A', sizeof(a));

    // Uses system memset for verification
    char b[10];
    memset(b, 'A', sizeof(b));

    assert(sizeof(a) == sizeof(b));
    assert(memcmp(a, b, sizeof(b)) == 0);
    return 0;
}

【讨论】:

    【解决方案3】:

    return p; 阻止它编译:p 未定义。

    一个小的效率问题——实际上它几乎没有效果,因为任何好的编译器都会重新排列它,但编码完美主义者不允许它保留——对temp的赋值在循环内部,但它是每次都是一样的任务。也就是说,temp 的赋值可以移到循环之前。

    【讨论】:

    • 我将其编辑为指针 :) 谢谢,但这不是问题,这只是复制、粘贴问题
    【解决方案4】:

    您返回p,它没有定义/没有特别指向任何东西。也许你的意思是pointer

    【讨论】:

      【解决方案5】:

      代码在逻辑上是正确的。使用p => pointer 更改它可以正常工作。

      澄清它究竟是如何“不工作”的。也许你不明白它应该做什么?

      【讨论】:

      • 它将垃圾编号放入值中,因此当您检查该值时(例如,当您要求该值为 2 时),您检查分配的字节的值并且值出来是随机数
      • @unknown 我们可以看到您用来检查值的代码吗?
      【解决方案6】:

      您可能会收到垃圾数字,因为您正在从 int(4 字节)转换为 unsigned char(1 字节),因此如果 c > 255 或

      【讨论】:

      • c 保证在 0 到 255 之间
      【解决方案7】:

      如果您的程序将 5 个元素的 int 向量的内存设置为值 0x01,我运行了一个测试。

      这里的问题是,您正在迭代一个 int 向量(例如 4 个字节),但使用 char 指针算法(1 个字节)对其进行迭代。例如,如果您想 memset 0x01,您将在向量中的每个值写入此数字:00000001000000010000000100000001 这给了我使用原始 memset 相同的值。

      【讨论】:

      • memset在C语言中定义为将int作为第二个参数。您假设 int 是 4 个字节 - 这不一定是真的。最后,我不知道你想用位模式说什么。
      • 好吧,自己运行程序。假设一个向量 int v[5];在那之后 memset(v, 0x01, sizeof(int)*5); memset 将在您的向量中写入 0x01010101,这似乎是错误的(有些人可能期望每个位置为 0x01),但事实并非如此。是的,你传递了一个 int 作为值,但是一个指针 void 作为内存缓冲区。
      • 关于位模式,你现在可能十进制的 1 等于十六进制的 0x01 等于二进制的 00000001 ;)。经过一番努力,那个大的二进制模式是十六进制的数字 0x01010101 或十进制的 16843009
      • memset 的定义方式,在这种情况下应该将内存设置为 0x01010101。 memset,根据定义,只向它写入的所有内存位置写入 一个 值。
      【解决方案8】:

      你的功能,原样,适合我。

      我想你说错了。我这样称呼它

      char a[100];
      memsetFun(a, 0, sizeof a);
      int b[100];
      memsetFun(b, 0, sizeof b);
      

      你怎么称呼你的memsetFun()

      编辑

      int b[100];
      memsetFun(b, 9, sizeof b);
      

      因为 int 由 4 个字节组成(在我的系统上),每个值将设置为 0x09090909151587081

      【讨论】:

        【解决方案9】:

        这正是它应该做的。您的功能运行良好。值“0x4”不是 ASCII 字符“4”。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2022-11-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-01-04
          相关资源
          最近更新 更多