9、内存操作
在实际项目设计中,内存操作随处可见,本文这里就重点将内存相关的操作符进行讲解和区分。
1、sizeof的用法
sizeof一般有以下两种用法:
第一种用法:
sizeof(type_name);//sizeof(类型名)
类型名称包括基本类型,也包括构造类型,如;
sizeof(int)、sizeof(U16)、sizeof(MATH_CUBE_ST)
第二种用法:
sizeof(var_obj_name);//sizeof(变量对象名称
如:
int val; u32 u32len; MATH_CUBE_ST stCube; sizeof(val) ; sizeof(u32len);sizeof(stCube);
在实际编程中,这两种方法都是可以的,但是一般建议用第二张种方法,以memset来举例,memset用来给指定地址的内存段指定相同的值,通常用来初始化变量,一般用法如下:
MATH_CUBE_ST stCube; memset(&stCube,0,sizeof(MATH_CUBE_ST)); //将变量stCube全部清零
这样写没有问题,但是每个人写程序时,后面都会用到复制粘贴,英雌我们复制时还要先去找定义行,然后进行复制,之后还要在找函数进行复制粘贴,如果两者距离很长的话,这样做明显是浪费时间且容易出错的,这是,第二种方法的好处就体现出来了,即:
memset(&stCube,0,sizeof(stCube));
这样问题就可以避免了。
2、sizeof的几个特例
1)、使用sizeof计算数组的大小及元素的个数
sizeof是在编译时进行计算的,因此可以将sizeof当作常量来对待,使用sizeof可以方便的计算数组所占用的内存大小,也可以计算元素的个数,在计算元素个数是,需要使用除法,示例如下:
/********************************************************** * 内容:测试sizeof函数计算数组大小 * 说明:无 * 日期:2017.11.1 * 版本:v1.0 ************************************************************/ #include <stdio.h> #include <string.h> unsigned int au32val[] = { 1,2,3,4,5 }; int main() { //输出数组au32val占用的字节数,4*5=20 printf("array length is %d\n ", sizeof(au32val)); //输出数组au32val的元素个数,5 printf("array element is %d\n", sizeof(au32val) / sizeof(unsigned int)); return; }
输出结果如下:
2)、使用sizeof计算新参数组
看如下示例:
/********************************************************** * 内容:使用sizeof计算新参数组 * 说明:无 * 日期:2017.11.1 * 版本:v1.0 ************************************************************/ #include <stdio.h> #include <string.h> int main(char abstract[3]) { printf("para len is %d\n", sizeof(abstract)); return; }
这里的结果并不是3,而是4,这里函数参数acStr已经不再是数组了,而是蜕变为了指针,相当于char *acStr,这里是因为数组是传“址”的,调用者只需将实参的地址传过去即可,所以acStr为指针类型(char*),程序结果输出也就是4;
(这里也引出了一个编程中的习惯,一般情况下是不要使用数组作为函数的参数,而是使用指针,如果要再想直到数组的长度,还需要添加一个长度的形参过来。
3)、字符串指针常量和数组字符串中的sizeof
先看示例如下:
/********************************************************** * 内容:字符串指针常量和数组字符串中的sizeof * 说明:无 * 日期:2017.11.1 * 版本:v1.0 ************************************************************/ #include <stdio.h> #include <string.h> int main() { char* pcpointStr = "123456789"; char acArrayStr[] = "123456789"; //输出字符串指针长度 printf("sizeof(pcpointStr)=%d\n", sizeof(pcpointStr)); //输出字符串指针指向内容的长度,结果为1 printf("sizeof(*pcpointStr)=%d\n", sizeof(*pcpointStr)); //输出数组的长度,记过为10,系统自动加结束符 printf("sizeof(acArrayStr)=%d\n", sizeof(acArrayStr)); //输出指针指向的变量长度,结果为1 printf("sizeof(*acArrayStr)=%d\n", sizeof(*acArrayStr)); return; }
通过上述示例可以看出指针和数组使用sizeof的区别,出现这样的区别的原因是,sizeof是在编译器直接计算出来的,其次是因为sizeof是计算的内存的大小,字符串指针的类型就是字符串指针类型,所以不管字符串的长度是多少,指针类型的长度都是4个字节,而数组字符串在sizeof下认为是数组类型,而数组类型编译时已经分配了大小,所以返回的为实际大小。
因此,无论是获取字符串指针指向内容还是字符串数组中的字符串长度,都应该用库函数strlen,而不是用sizeof;
2、memset和memcpy
1)、memset
在之前讲解sizeof时,我们已经用到过memset函数,这里将对其进行详细讲解和示例分析。其函数原型如下所示:
void *memset(void *dest, int c, size_t counter);
memset函数的作用是将缓存设定为一个专门的字符,对照函数原型,就是将已经开辟内存空间dest的首count个字节的值设定为c。
示例如下:
/********************************************************** * 内容:测试memset函数 * 说明:无 * 日期:2017.11.1 * 版本:v1.0 ************************************************************/ #include <stdio.h> #include <string.h> int main() { char TestStr[] = "AAAAAAAAAAAAA"; printf("The original string is :%s\n", TestStr); memset(TestStr, 'C', 3);//将TestStr的前三个字符替换成C printf("the change string is :%s\n", TestStr); return 0; }
结果为:
2)memcpy
函数原型如下
void *memcpy(void *dest,const void *src, size_t count);
memcpy函数的作用是在缓存之间复制字符,对照函数原型,memcpy即用来复制src所指向的内存内容的前count个字节到dest所指的内存地址上。
示例如下:
/********************************************************** * 内容:测试memcpy函数 * 说明:无 * 日期:2017.11.1 * 版本:v1.0 ************************************************************/ #include <stdio.h> #include <string.h> typedef signed char INT8;//重定义数据类型 typedef signed int INT32; int main() { char szTestStr[100] = "AAAAAAAAAAAAA"; char szCopyStr[100] = "HELOWORLD"; printf("The original string is :%s\n", szTestStr); memcpy(szTestStr, szCopyStr+2, 3);//将TestStr的前三个字符替换成从szCopy第3个字符开始三个字符 printf("the change string is :%s\n", szTestStr); return 0; }
值得注意的是:src与dest所指向的内容不能叠加,函数返回值为指向dest的指针。
在实际项目中,两者经常同时使用,即先用memset初始化某数组或结构体,然后用memcpy将内容复制到被初始化的变量中。
char szStringContent[1024] = { 0 }; ...... memset(szStringContent, 0x00, sizeof(szStringContent)); memcpy(szStringContent, "li", strlen("li")); ......