memset()函数的使用注意
最近,同事在负责一个项目的时候遇到一个问题:数组初始化后值异常,后来找出是使用memset函数的锅,这里我也来跟着学习下。。
C语言中memset源码如下:
void *memset(void *s, int c, size_t count) { char *xs = s; while (count--) *xs++ = c; return s; }
我们可以发现,在memset()函数中,会将(void *)类型转换成(char *)类型,这样会有什么影响呢?
1、试验一
#include <stdio.h> #include <string.h> int main(void) { int i=0,j=0; int array_1[16]; char array_2[16]; memset(array_1, 0, 16); memset(array_2, 0, 16); printf("[array_1]:"); for(i; i<16; i++) { printf("%d ",array_1[i]); } printf("\n"); printf("[array_2]:"); for(j; j<16; j++) { printf("%d ",array_2[j]); } printf("\n"); return 0; }
这里分别设置两个类型的数组,一个int型,一个char型,那么输出结果如下:
[array_1]:0 0 0 0 1835627636 1600061541 1869833334 1952802655 1 0 4196205 0 0 0 0 0
[array_2]:0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
可以发现,这时候int型的数组初始化是异常的。若细心一点可以发现,int型数组的前4个成员都是为0的(16个字节),这个长度刚好是array_2的长度。那这是不是由于memset是以char为单位进行置0,所以只初始化了int型数组的前四个成员呢?
2、试验二:
memset(array_1, 0, 64);
那么输出结果如下:
[array_1]:0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
[array_2]:0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
可以发现,int型数组初始化完成了。那么是不是指针转换是数据丢失呢?
3、实验三:
#include <stdio.h> #include <string.h> int main(void) { int *addr_1 = (int *)0x12345678; char *addr_2 = (void *)addr_1; printf("addr_1 : %p\n",addr_1); printf("addr_2 : %p\n",addr_2); return 0; }
那么输出结果如下:
addr_1 : 0x12345678
addr_2 : 0x12345678
也是就说,不同类型的指针的指针长度是一样的,但是,指针偏移的时候会根据所声明的类型来进行偏移。如同样是prt++,int *表示偏移是4个字节,char *则表示偏移是1个字节
既然这样的话,那么如果结构体里面成员类型不同的话,那么结构体的初始化也会有影响吗?
4、实验四:
#include <stdio.h>
#include <string.h>
typedef struct _s_param
{
int a;
int b;
char c;
}S_PARAM;
typedef struct _s_var
{
char a;
char b;
int c;
}S_VAR;
int main(void)
{
S_PARAM param;
S_VAR var;
memset(¶m, 0, sizeof(S_PARAM));
memset(&var, 0, sizeof(S_VAR));
printf("[param(%ld)] a=%d, b=%d, c=%d\n",sizeof(S_PARAM), param.a,param.b,param.c);
printf("[var(%ld)] a=%d, b=%d, c=%d\n",sizeof(S_VAR), var.a,var.b,var.c);
}
那么输出结果如下:
[param(12)] a=0, b=0, c=0
[var(8)] a=0, b=0, c=0
可以发现结构体的初始化是正常的,这是因为输入的长度是结构体的长度,那这样的话,那前面的数组初始化用sizeof的话,应该也是初始化正常的(这里就不进行实验啦)