关于栈空间和堆空间的问题

操作系统对于内存的两种管理方式

如鹏网 《C语言也能干大事》http://www.rupeng.com/Courses/Index/12

第三章透彻讲指针 之  第 15 节: 栈空间 

平时我们定义的变量都是分布在栈空间里,如下面的程序所示

1 #include <stdio.h>
2 int main(int argc, char *argv[])
3 {
4     int i=5;
5     char s[] = "afasdfsfwfw";    
6     return 0;
7 }

栈空间:出了函数范围,内存空间自动释放。定义的局部变量int、局部数组等都在栈空间中。栈空间的尺寸有最大的限制,不适合分配大空间使用;栈空间出了函数范围就释放,不适合要给其他地方使用的内存。好处:不需要手动释放。

 1 #include <stdio.h>
 2  
 3 int *getData()
 4 {
 5     int nums[10]={1,2,3,4,5,6,7,8};
 6     return nums;
 7 }
 8  
 9 int *getData3()
10 {
11      int i=5;
12      return &i;
13 }
14  
15 int *getData2()
16 {
17     int aaa[10]={8,7,6,5,4,3,2,1};
18     return aaa;
19 }
20  
21 int main(int argc, char *argv[])
22 {
23     int * nums = getData();
24     getData2();
25     printf("%d,%d,%d",nums[0],nums[1],nums[2]);
26     return 0;
27 }

上面程序第24行,如果注释getData2(),上述程序的执行结果是1,2,3

但是如果不注释getData2(),上述程序的执行结果是:8,7,6

这里很好的反映了栈空间的问题,因为注释getData2()时,函数getData1()申请了栈空间存储数组{1,2,3,4,5,6,7,8},指针num指向该数组首地址,所以打印输出结果为1,2,3;但是一旦加入getData2(),因为getData1()执行完毕退出了,它申请的内存空间(存储数组的)就被释放掉了,再执行getData2(),该函数同样申请内存空间{8,7,6,5,4,3,2,1}覆盖了前述的数组{1,2,3,4,5,6,7,8}占用内存,故输出结果变成了8,7,6。

注意:因此这里有一个编程规范,不要把局部变量的指针作为函数返回值返回

 第二部分是堆空间的学习内容

堆空间:手动分配,使用完成之后需要手动释放。使用malloc分配,使用free释放。执行下列代码,会看到程序的内存在暴涨

要在内存

优点:可以动态分配内存,分配比较大的内存,比如下载软件每下载10M,才把缓冲区(分配的动态内存)的数据写入磁盘。

下面是跟前面一样的功能样例,但是使用了动态内存分配,也就是堆空间的方法,最终打印输出结果为1,2,3

 1 #include <stdio.h>
 2 #include <stdlib.h>//malloc在该头文件中声明
 3 int *getData1()
 4 {
 5     int *nums = (int *)malloc(sizeof(int)*3);
 6     nums[0] = 1;
 7     nums[1] = 2;
 8     nums[2] = 3;
 9     return nums;
10 }
11 int *getData2()
12 {
13     int *nums = (int *)malloc(sizeof(int)*3);
14     nums[0] = 4;
15     nums[1] = 5;
16     nums[2] = 6;
17     return nums;
18 }
19 int main(int argc, char *argv[])
20 {
21     int *num1 = getData1();
22     int *num2 = getData2();
23      printf("%d,%d,%d
",num1[0],num1[1],num1[2]);
24     free(num1);//由调用者释放内存,如果不释放,会导致内存泄露
25     free(num2);
26     return 0;
27 }

函数返回指针的方法

方法1:在方法内malloc,用完了由调用者free

方法2:把局部变量定义为static,不适合于多线程调用,如果想保存返回内容,你需要调用者尽快复制一份。

方法3:由调用者分配内存空间,只是把指针发给函数,函数内部把数据拷贝到内存中(推荐)。案例:从文件名分析文件名和扩展名。

 1 #include <stdio.h>
 2 #include <string.h>
 3  
 4 void parseFileName(char* filename,char* name,
 5     char* ext)
 6 {
 7     char *ptr=filename;
 8  
 9     while(*ptr!='')
10     {
11         ptr++;
12     }
13     char *endPtr = ptr;//结尾的指针
14     //ptr移动到了字符串的结尾
15     //再把ptr移动到"."的位置
16     while(*ptr!='.')
17     {
18         ptr--;
19     }
20     memcpy(name,filename,(ptr-filename)*sizeof(char));
21     memcpy(ext,ptr+1,(endPtr-ptr)*sizeof(char));
22 }
23  
24 int main(int argc, char *argv[])
25 {
26     char str[]="[TK-300]美.女.avi"; //调用者分配内存空间
27     char name[20]={0};//调用者分配内存空间
28     char ext[20]={0};//调用者分配内存空间
29     parseFileName(str,name,ext);
30     printf("文件名:%s,后缀:%s",name,ext);
31     return 0;
32 }

 补充:memset()与memcpy()的功能?

    strcpy()与strcpy_s()的差别?

原文地址:https://www.cnblogs.com/codecamel/p/4590424.html