综述
首先,memset是一个比较*疼的东西,主要原因是它当初被设计出来主要是用来为字符串(比如char型数组)赋值的,但是当大家把它拿来给其他类型(比如int,double等)赋值的话,就该*疼了——
头文件与函数原型
之所以说memset用来处理字符串,可以行它的头文件略见一斑
string.h
这显然是来处理字符串的啊。
void * memset (void * p,int c,size_t n);
由原型可以看出:指针p为所操作的内存空间的首地址,c为每个字节所赋的值,n为所操作内存空间的字节长度,也就是内存被赋值为c的字节数。
举例及注意事项
下面问题来了,memset究竟要注意什么?
举个例子:
char a[10];
memset(a, '\n', 10);
这个例子说明了将一个10个字节的char型数组全部赋值为10个'\n',这当然可以,因为memset本来就是处理字符或字符串的。
问题是如果处理其他类型呢?
再举个例子:
int a[10];
memset(a, 1, 10);
结果是什么呢?是将10个int型的数组a全部赋值为整数1吗?显然不是的。
我们不妨从底层来看:一个int有4个字节,也就是说数组a其实是一个连续40个字节的存储空间。而memset(a, 1, 10)代表将10个字节赋值为1,也就是说a[0] = a[1] = 0x01010101,a[2] = 0x01010000,a[3] = a[4] = ... = a[9] = 0。
所以,赋值显然是失败的。失败的根源就是memset本来就是用来处理字符,按照字节来操作的,所以对其他类型的数据操作一定要慎重!
不过初始化(赋0值)int型数组倒是可以的:
int a[10];
memset(a, 1, 10*sizeof(int));
号外
对赋值的理解:
<span style="font-size:18px;">char c = 1;</span>
对于上面的代码,我们可以这样理解——
(1)从实际内存操作上看,上面的代码表示对c代表的字节赋1;
(2)从逻辑内容上看,上面的代码表示将c赋值为ASCII值1所代表的字符。
int m = 7;
int n = 8;
int i;
int **a; //用malloc申请建立二维数组
a = (int **) malloc(m * sizeof(int *));
for(i=0; i<m; ++i)
a[i] = (int *) malloc(n * sizeof(int));
memset(a, 0, sizeof(int) * m * n); //wrong!!!
但是
int a[7][8];
memset(a, 0, 7*8*sizeof(int));
对这种定义的二维数组是可以的。因为这种申请方式保证了数组内存地址是连续的。
号外(临时补充内容):
<span style="font-size:18px;">char c = 1;</span>
对于上面的代码,我们可以这样理解——
(1)从实际内存操作上看,上面的代码表示对c代表的字节赋1;
(2)从逻辑内容上看,上面的代码表示将c赋值为ASCII值1所代表的字符。