C/C++内存存储问题
#include <stdio.h>
#include "string.h"
#include "malloc.h"
void Swap(int a,int b)
{
int temp;
temp=a;
a=b;
b=temp;
}
int Get_Int(int a)
{
+a;
return i;
}
char* Get_Memory0()
{
);
strcpy_s(p,"hello world");
return p;
}
char* Get_Memory1()
{
char* p="hello world";
return p;
}
char* Get_Memory2()
{
char p[]="hello world";
return p;
}
void main()
{
,y=;
Swap(x,y);
int z=x-y;
printf("z=%d\n",z);
z=Get_Int(z);
printf("z=%d\n",z);
char* c0=Get_Memory0();
printf("c0=%s\n",c0);
const char* c1=Get_Memory1();
printf("c1=%s\n",c1);
char* const c2=Get_Memory2();
printf("c2=%s\n",c2);
}
面试题,上面的程序执行结果是什么?
基础知识
内存存储:
在C/C++中,通常可以把内存理解成4个分区:栈、堆、全局/静态存储区和常量存储区。
(1)栈:通常是用那些在编译期间就能确定其存储大小的变量的存储区,用于在函数作用域内创建、在离开作用域后自动销毁的变量的存储区。通常是局部变量、函数参数等的存储区。它的存储空间是连续的,两个紧挨着的定义的局部变量,它们的存储空间是紧挨着的。栈的大小是有限的,通常Visual C++编译器默认栈的大小是1M,所以不要定义int a[1000000]这样的超大数组。
(2)堆:通常是用于那些在编译期间不能确定存储大小的变量存储区,它的存储空间是不连续的,一般同malloc(或new)函数来分配内存块,并且需要要free(或delete)释放内存。如果程序员没有释放掉,那么就会出现常说的内存泄漏问题。需要注意的是,两个紧挨定义的指针变量,所指向的malloc出来的内存并不一定是紧挨着的。另外需要注意的一点是,堆的大小几乎是不受限制的,理论上每个程序最大可达4GB。
(3)全局/静态存储区:和“栈”一样,通常是用于那些在编译期间就能确定存储大小的变量的存储区,但它用于的是在整个程序运行期间都可见的全局变量和静态变量。
(4)常量存储区:和“全局/静态存储区”一样,通常是用于那些在编译期间就能确定存储大小的常量存储区,并且在程序运行期间,存储区内的常量也是全局可见的。这是一块比较特殊的存储区,它们里面放的是常量,不允许被修改。
程序解答:
(1)Swap函数:我们知道,所有函数都会在运行时从程序“栈”上得到分配给它的一块存储区(这里的“栈”就是前两面讲解内存存储时提到的“栈”,第个运行程序都拥有自己的运行时“栈”)。这块“栈”上的函数存储区随函数的开始面开始,随着函数的结束而结束。函数结束后,这块存储区就会自动释放,以供程序的其他用途使用。系统在函数运行时会为函数的每一个参数都提供存储区,参数在存储区中的存储长度由自身的类型决定。参数传递,就是系统用函数实参初始化函数参数存储区的过程。
函数的参数有传值(传指针)和传址(传引用)两种。所谓参会传值,就是实参的值复制到函数运行时分配给函数的参数存储区中。参数在传值时,函数不会访问当前调用的实参,函数处理的是实参在本地的拷贝,这些拷贝被存储在函数的“栈”中,所以这些拷贝值的改变不会影响实参的值。
答案:
z=1
(2)问题:返回值i是一个局部变量,函数的返回参数怎么能是局部变量呢?局部变量在离开作用域后就自动被销毁了,还怎么能返回值给调用都呢?
解答:函数的返回值有传值和传址两种。int Get_Int(int a)属于返回值是传值的函数,这就意味着函数int Get_Int(int a)会在函数返回处产生一个临时对象,用于存放局部变量i的值的一份拷贝(变量i的右值的拷贝),临时对象是没有名称的,这份没有名称的对象的值(右值)会存储在调用者的“栈”中。所以当i作为局部变量离开作用域后,虽然被销毁了,但它的拷贝仍然存在,并在函数返回时作为“右值”赋给“左值z”。
答案:
z=2
(3)此处考查对“堆”的理解:函数返回的是指向“堆”内存的指针。程序中malloc()是用于分配“堆”内存的库函数,而对于“堆”内存,只要程序中没有调用free()库函数去释放掉该“堆”内存,那么在程序运行期间,malloc()库函数分配的“堆”内存将一直存在。
char* p=(char*)malloc(sizeof(char)*20)表示分配一块“堆”内存并使得变量p指向这块“堆”内存。
strcpy(p,"hello world")表示往p指向的“堆”内存中复制字符串hello world。
return p,变量p的左值是一个局部变量指针,存储于函数栈上,右值 是“堆”的地址(“堆”的值是hello world)。
函数char* Get_Memory0()属于返回值是传指针的函数,这就意味着函数char* Get_Memory0()会在函数返回处产生一个对返回变量p的“左值”的拷贝,也就是在“左值”的拷贝中存储了指向“堆”的地址。作为局部变量的 p,在离开函数作用域的时候虽然被销毁了,但函数返回值珠“左值”的拷贝是存在的,该拷贝存储了指向“堆“的地址,而而该“堆”的值是hello world。
答案:
c1=hello world
(4)这里考查对函数返回值和指针的理解:变量分为左值和右值,在char* p="hello world"中,左值是局部变量指针p,存储于函数栈上,右值是字符串常量hello world,存储于常量存储区。
char* Get_Memory1()属于返回值是传指针的函数,这就意味着函数char* Get_Memory1()会在函数返回处产生一个对返回对象的“左值”的拷贝,也就是在“左值”拷贝中存储了指向字符串常量hello world的地址。作为局部变量的p,在离开函数作用域的时候虽然被销毁了,但函数 返回的“左值”拷贝仍然存储了指向常量存储区的字符串常量hello world的地址。
答案:
c1=hello world
(5)和问题(4)有些相似,考查的也是对函数返回值和指针的理解:返回值是传指针,会在函数返回时产生“左值”拷贝。可以看到,p[]不是指针,是一个数组变量。编译器根据右值“hello world”的长度(12个字符)在编译期间在函数的栈上为数组分配大小为12个字符的内存存储区,其值是“hello world”。
通常,变量的意义在于,它给一块内存存储区提供名字,方便程序对这块内存进行读写。变量包含两个值:左值和右值。左值是内存存储区的名字,右值是存放存储区中的值。从程序中可以看到,函数返回的“左值”拷贝 指向的是局部变量数组p[12]的首地址。当局部数组p[12]作用域后会被自动销毁。这时,函数返回的“左值”拷贝指向的是一个被销毁的局部变量地址。
答案:
warning C4172: returning address of local variable or temporary
c2=未知
C/C++内存存储问题的更多相关文章
- Redis内存存储结构分析
1 Redis 内存存储结构 本文是基于 Redis-v2.2.4 版本进行分析. 1.1 Redis 内存存储总体结构 Redis 是支持多key-value数据库(表)的,并用 RedisDb 来 ...
- C/C++内存存储
#include <stdio.h> #include "string.h" #include "malloc.h" void Swap(int a ...
- memcached全面剖析–2. 理解memcached的内存存储
Slab Allocation机制:整理内存以便重复使用 最近的memcached默认情况下采用了名为Slab Allocator的机制分配.管理内存. 在该机制出现以前,内存的分配是通过对所有记录简 ...
- 1.C#基础学习笔记3---C#字符串(转义符和内存存储无关)
技术qq交流群:JavaDream:251572072 教程下载,在线交流:创梦IT社区:www.credream.com ------------------------------------- ...
- 【解惑】剖析float型的内存存储和精度丢失问题
问题提出:12.0f-11.9f=0.10000038,"减不尽"为什么? 现在我们就详细剖析一下浮点型运算为什么会造成精度丢失? 1.小数的二进制表示问题 首先我们要搞清楚下面两 ...
- Go Web:数据存储(1)——内存存储
数据可以存储在内存中.文件中.按二进制序列化存储的文件中.数据库中等. 1.内存存储 2.CSV文件存储 3.gob序列化存储 内存存储 将数据存储到内存中.此处所指的内存是指应用程序自身的内存空间( ...
- memcached全面剖析--2.理解memcached的内存存储
下面是<memcached全面剖析>的第二部分. 发表日:2008/7/9 作者:前坂徹(Toru Maesaka) 原文链接:http://gihyo.jp/dev/feature/01 ...
- spark 源码分析之十六 -- Spark内存存储剖析
上篇spark 源码分析之十五 -- Spark内存管理剖析 讲解了Spark的内存管理机制,主要是MemoryManager的内容.跟Spark的内存管理机制最密切相关的就是内存存储,本篇文章主要介 ...
- 32 位bitmap 内存存储 顺序 bgra 前3位 与23位一致。 都是 bgr 呵呵 与rgb 相反
32 位bitmap 内存存储 顺序 bgra 前3位 与23位一致. 都是 bgr 呵呵 与rgb 相反
随机推荐
- 浅谈JVM内存区域划分
好吧,虽说真的有看过<深入分析Java Web技术内幕>一书,但当时看的时候还是一知半解,稀里糊涂的看完了.本来是打算暑假拿起来再看一遍的,但是早两天一个阿里学长给我做了个小面试,让我颇受 ...
- Unity性能优化
一.优化组件访问方式 原文:http://blog.csdn.net/lijing_hi/article/details/11657887 1.缓存Component的引用,如transform 2. ...
- 程序员必备基础知识:通信协议——Http、TCP、UDP
CP HTTP UDP: 都是通信协议,也就是通信时所遵守的规则,只有双方按照这个规则“说话”,对方才能理解或为之服务. TCP HTTP UDP三者的关系: TCP/IP是个协议组,可分为四个层次: ...
- (转)iOS7界面设计规范(8) - UI基础 - 术语和措辞
讨厌周一,讨厌一周.今天中午交互组聚餐,却很开心:大家都是很厉害的人,你可以感到他们身上的能量,可以感到有些什么东西正在推着自己尽力向前走.这是一种很健康的状态,同时也很难得,自然越发需要珍惜.从无到 ...
- core_cm3文件函数一览
core_cm3是ARM公司推出来的统一规定,这是对下游芯片厂商的统一规定,因此可以再Cortex-M3(CM3)之间进行移植.此文件中定义了一些对特殊功能寄存器的C语言形式的操作,本质上是内敛汇编和 ...
- [Redux] Extracting Presentational Components -- Footer, FilterLink
Code to be refactored: let nextTodoId = 0; class TodoApp extends Component { render() { const { todo ...
- 畅通project
原文请訪问:p=174">http://xiaoshig.sinaapp.com/?p=174 畅通project Time Limit:2000MS Memory Limit ...
- jQuery中 $ 符号的冲突问题
jQuery中 $ 符号的冲突问题是常见问题之一. 在jQuery中,$是jQuery的别名,为了书写方便,我们更习惯用$('#id')这一类的方式来书写代码.当同一页面引用了jQuery多个版本 ...
- C语言中static关键字的作用
static的作用(精辟分析) 在C语言中,static的字面意思很容易把我们导入歧途,其实它的作用有三条. (1)先来介绍它的第一条也是最重要的一条:隐藏. 当我们同时编译多个文件时,所有未加sta ...
- CSS基础知识笔记(一)
css 样式由选择符和声明组成,而声明又由属性和值组成: 选择符: 又称选择器,指明网页中要应用样式规则的元素,如本例中是网页中所有的段(p)的文字将变成蓝色,而其他的元素(如ol)不会受到影响. 声 ...