正确使用memset
今天做了一道素数打表的题我在使用一个数组记录是否为素数的时候使用了memset,将数组里面的数都清为1,代表是素数,不是素数,就改成0,我在判断这一个数是否为素数是依据也是是0还是1,结果一直存在问题,经过我一步步的调试竟然发现了一个之前从未在意过的bug,memset只能将int型数组清理成0或-1!!!
我们来验证一下:
#include <stdio.h> #include <string.h> int main() { int array[5]; int a; while(~scanf("%d",&a)){ memset(array,a,sizeof(array)); printf("%d %d\n",array[0],array[1]); } return 0; }
程序功能:初始化数组元素为输入值。
输入:
-1
0
1
预期输出:
-1 -1
0 0
1 1
实际输出:
-1 -1
0 0
16843009 16843009
原因:
memset是按字节赋值的,取变量a的后8位二进制进行赋值。
1的二进制是(00000000 00000000 00000000 00000001),取后8位(00000001),int型占4个字节,当初始化为1时,它把一个int的每个字节都设置为1,也就是0x01010101,二进制是00000001 00000001 00000001 00000001,十进制就是16843009。
之所以输入0,-1时正确,原理是这样的。
0,二进制是(00000000 00000000 00000000 00000000),取后8位(00000000),初始化后00000000 00000000 00000000 00000000结果是0
-1,负数在计算机中以补码存储,二进制是(11111111 11111111 11111111 11111111),取后8位(11111111),则是11111111 11111111 11111111 11111111结果也是-1
这是c标准库里面的memset的原码:
1 void *(memset)(void *s, int c, size_t n) 2 { 3 const unsigned char uc = c; 4 unsigned char *su; 5 for (su = s; 0 < n; ++su, --n) 6 *su = uc; 7 return (s); 8 }
源码说明对于数组参数是按照字符数组的形式进行赋值的。
当初始化一个字节单位的数组时,可以用memset把每个数组单元初始化成任何你想要的值,比如,
1 char data[10]; 2 memset(data, 1, sizeof(data)); // right 3 memset(data, 0, sizeof(data)); // right
而想要将int型数组赋值成自己想要的值,我只会自己DIY了
1 int a[11]; 2 for(int i=0; i<sizeof(a)/sizeof(int); i++) 3 { 4 a[i]=1; 5 }