一转眼,工作也半年了,工作也如愿的成了一名C程序猿,驿站给了我很多帮助,想想自己也可以算是驿站的“老人”了,可是自己技术不精,学的又太浅,一直也不能写点啥有意义的帖子。最近工作时候,由于我写的代码内存的问题,导致设备死机查了很久,后来又好好学了学关于内存的分配相关的知识,小小的写点心得,因为技术有限,总结的不好,希望大家多多包函并给出补充。
首先说下内存分配的方式吧,上次一位大牛在公司发邮件,告诉我们内核栈区只有4M,要求我们写代码的时候不用结构体数组,比如
struct Abc
{
\\.....
}
这样一个结构体,在函数中不让我们写
Abc abc[MAX];
应该写成
Abc* abc;
abc = (Abc *)malloc( MAX*(sizeof( struct Abc)));
当时我很不理解,这样大小不是一样的吗?后来查了相关资料,发现自己原来学习不求甚解,真害了自己。书上清清楚楚写着,动态分配内存是从堆中分配,而局部变量是从栈上创建,当时看的时候哪里管那么多,感觉都一样,原来差别很大啊。当然这东西很基础,我觉着也许还有些初学者会忽视堆、栈相关的内容吧,其实这挺重要的,我来说说它们的区别吧。内存区应该分为三块吧
1、静态存储区域 这块内存是在程序编译就分配好的,在整个程序运行期间都存在,主要是用来放一些全局变量呀,static变量还有一些常量的
2、栈区 我们老工程师说的4M的内核栈就是栈区,这块主要是存放局部变量的,函数执行完后存储单元被自动释放。栈的优点是效率较高,缺点就是空间相对较有限。
3、堆区 我们动态分配内存的时候就是从这块区域来申请的,比如malloc和free,new和delete,这块区域相对较大,而且什么时候用什么时候释放我们说了算,很灵活,但是忘记释放会很麻烦。。。
说说我上次犯过的一个错吧。是一个字符串处理的函数,有一个全局字符串指针data,我写的函数大体是
char mstr[MAX]={0};
dstr = data;\\dstr也是一个全局指针
int i = 0;
while(*dstr != '\0')
{
if((*dstr=='X')&&(*(dstr+1)=='X'))
{
dstr+=2;
continue;
}
mstr[i++] = *dstr++;
}
data=mstr ;
data主要是在这里处理一下,别处还要用,结果我再用的时候总是没有东西,其实挺简单的,当时就没看出来,这mstr是在这个函数里面的,函数结束了,也就没有了。。。当然,这是个破问题,不值得一提,还是说下比较容易犯的问题吧
比较低级但也比较容易犯的,内存没有分配成功就用了。比如我前面写的abc = (Abc *)malloc( MAX*(sizeof( struct Abc)));应该加个保护if(NULL == abc)就返回类似的,就可以避免内存未分配成功就使用的问题了。当然,分配成功了,就不要忘记释放,否则会造成内存泄露,这样,每当你的函数掉用一次,就浪费一段内存区,到时候突然内存不足了,才可能发现。。。这个一定要记得牢牢的。释放了不算完事,要记着给你的指针赋值NULL避免产生野指针。比如free(p);p=NULL;
其实说到这里差不多该说完了,但是说起指针了,不能不说下它和数组之间的一些事了。
这里很多是我从网上查的,加上自己的理解。首先在一个函数中,如果你写char a[]="hello";那么这里的hello这个字符串为数组a的内容,也就是存在栈区的,你可以自己改,比如a[0]='y';这样是没有问题的,但是char* p="hello";就不一样了,p是在栈里的指针,但指向的内容却是静态区的字符串常量hello,不可以随便更改,可能说的有点绕,比如函数结束了,指针p被销毁了,但是字符串hello却没有被销毁。这样也会有一个有意思的事,比如说
char* getString()
{
char a[]="bbb";
return a;
}
你再p=getString();得到p中内容将会为未知内容,因为这里bbb只是数组a的内容,getString()结束后,a销毁,其内容bbb也会销毁,但是如果你写
char* getString()
{
char* pst = "bbb";
return pst;
}
p=getString();p就是bbb了,因为bbb是静态区的,哈哈。
以上也就是我近日所理解的,总结的估计也不是很全,大家有啥跟帖补充一下吧,希望能对大家有用。