c语言中的堆和栈的区别(共9篇)由网友“桃花心肠”投稿提供,下面是小编整理过的c语言中的堆和栈的区别,欢迎您阅读,希望对您有所帮助。
篇1:c语言中的堆和栈的区别
堆和栈的区别
1.申请方式
(1)栈(satck):由系统自动分配,例如,声明在函数中一个局部变量int b;系统自动在栈中为b开辟空间。
(2)堆(heap):需程序员自己申请(调用malloc,realloc,calloc),并指明大小,并由程序员进行释放。容易产生memory leak.
eg:char p;
p = (char *)malloc(sizeof(char));
但是,p本身是在栈中。
2.申请大小的限制
(1)栈:在windows下栈是向底地址扩展的数据结构,是一块连续的内存区域(它的生长方向与内存的生长方向相反)。栈的大小是固定的。如果申请的空间超过栈的剩余空间时,将提示overflow。
(2)堆:堆是高地址扩展的数据结构(它的生长方向与内存的生长方向相同),是不连续的内存区域。这是由于系统使用链表来存储空闲内存地址的,自然是不连续的,而链表的遍历方向是由底地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。
3.系统响应:
(1)栈:只要栈的空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
(2)堆:首先应该知道操作系统有一个记录空闲内存地址的链表,但系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的free语句才能正确的释放本内存空间。另外,找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。
说明:对于堆来讲,对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低,
对于栈来讲,则不会存在这个问题,
4.申请效率
(1)栈由系统自动分配,速度快。但程序员是无法控制的
(2)堆是由malloc分配的内存,一般速度比较慢,而且容易产生碎片,不过用起来最方便。
5.堆和栈中的存储内容
(1)栈:在函数调用时,第一个进栈的主函数中后的下一条语句的地址,然后是函数的各个参数,参数是从右往左入栈的,然后是函数中的局部变量。注:静态变量是不入栈的。
当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续执行。
(2)堆:一般是在堆的头部用一个字节存放堆的大小。
6.存取效率
(1)堆:char *s1=”hellow tigerjibo”;是在编译是就确定的
(2)栈:char s1[]=”hellow tigerjibo”;是在运行时赋值的;用数组比用指针速度更快一些,指针在底层汇编中需要用edx寄存器中转一下,而数组在栈上读取。
补充:
栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。
7.分配方式:
(1)堆都是动态分配的,没有静态分配的堆。
(2)栈有两种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的。它的动态分配是由编译器进行释放,无需手工实现。
篇2:堆和栈的区别
空间分配区别
栈(操作系统):由操作系统(编译器)自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的'栈。堆(操作系统):一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。
堆栈缓存方式区别
栈使用的是一级缓存,它们通常都是被调用时处于存储空间中,调用完毕立即释放。堆则是存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定(并不是一旦成为孤儿对象就能被回收)。所以调用这些对象的速度要相对来得低一些。
篇3:C语言中break与continue的区别
C语言中break与continue的区别
break 关键字很重要,表示终止本层循环,现在这个例子只有一层循环,当代码执行到break 时,循环便终止。
如果把break 换成continue 会是什么样子呢?continue 表示终止本次(本轮)循环。当代码执行到continue 时,本轮循环终止,进入下一轮循环。
while(1)也有写成while(true) 或者while(1==1) 或者while((bool) 1)等形式的,效果一样。
do-while 循环:先执行do 后面的代码,然后再判断while 后面括号里的值,如果为真,循环开始;否则,循环不开始。其用法与while 循环没有区别,但相对较少用。
for 循环:for 循环可以很容易的控制循环次数,多用于事先知道循环次数的情况下,
《C语言中break与continue的`区别》()。
拓展:
我有一个char * 型指针正巧指向一些int 型变量, 我想跳过它们。 为什么如下的代码((int *)p)++; 不行?
在C 语言中, 类型转换意味着“把这些二进制位看作另一种类型, 并作相应的对待”; 这是一个转换操作符, 根据定义它只能生成一个右值(rvalue)。而右值既不能赋值, 也不能用++ 自增。(如果编译器支持这样的扩展, 那要么是一个错误, 要么是有意作出的非标准扩展。) 要达到你的目的可以用:p = (char *)((int *)p + 1);
或者,因为p 是char * 型, 直接用p += sizeof(int);
但是, 在可能的情况下, 你还是应该首先选择适当的指针类型, 而不是一味地试图李代桃僵。
篇4:C语言中的const
C语言的中的const,代表的含义是”不可改变的变量“,或者可以成为”伪常量“
C++中 const,被称为”一个有类型描述的常量“
const int liv_num = 10; liv_num = 18; //error 因为liv_num 被const修饰不可被直接赋值
那么,我为什么说是”伪常量“?
我们知道在c中给变量赋值,有两种方式:一种就是直接赋值;一种是间接赋值,
对于第一种方式,我们已经验证是不可以的。那么,使用间接赋值是否可以实现对liv_num的值得改变呢?
注意:一定要是.c的文件,如果使用的是.cpp的话,不会出现效果,因为c++中 const,被称为”一个有类型描述的常量“
#include
通过以上,我们就方向 在c中 const 是 ”伪常量“, 那么也说明一个问题,const是保存在 ”栈“ 中的, 如果想验证,可以使用debug,观察内存,再此不在叙述,
篇5:浅谈C语言中scanf,gets函数区别与联系
众所周知,scanf函数和gets函数是从键盘输入数据的函数,其基本函数功能这里不做过多赘述,只对两个函数易错点深入分析。
int main(){ char a[20]; char b[20]; char c[20]; printf(“请输入a字符串\n”); scanf(“%s”,&a); printf(“请输入b字符串\n”); gets(b); printf(“请输入c字符串\n”); gets(c); return 0;}
【分析】程序本意是输入三个字符串,之所以用printf提示输入是因为想更清楚地看清程序怎么运作的,可以从运行界面看到程序提示输入a字符串和c字符串,但是会越过b字符串不让输入。这里会让人感到困惑。
因为scanf函数在读取字符串时,遇到回车、空格、制表符不会进行读取或转换,会舍弃掉它们以及它们后面的字符至缓冲区,最后在读取的字符后面加上‘\0’.因此到了gets(b)的时候就会读取缓冲区剩下的东西以及最后的换行符就结束了,所以程序不会提示输入b字符串,但是从监视可以看到b中其实是读取了字符串的。然后缓冲区无剩余字符gets(c)可以实现输入c字符串。而且从这个程序也可以体现出来需要用到里面有空格的字符串的时候可以用gets函数。
这里还有一个注意点:在gets(c)读取从键盘输入的字符以及最后需要将缓冲区的数据刷新出去的回车符。它和scanf不同的是不会舍弃回车符至缓冲区中, 而是会丢弃换行符将其改为字符串结束标志‘\0’,
所以我们一般喜欢使用这种带有清理收尾工作的输入函数。
最后一个点,我们可以看到b字符串其实读取的是缓冲区中的垃圾数据。因此,为了避免输入流缓冲区中垃圾数据对后续读入的影响,需要清空缓冲区。
下面就介绍方法(不同平台)
C标准规定 fflush()函数是用来刷新输出(stdout)缓存的。对于输入(stdin),它是没有定义的。但是有些编译器也定义了 fflush( stdin )的实现,比如微软的VC。其它编译器是否也定义了 fflush( stdin )的实现应当查找它的手册。GCC编译器没有定义它的实现,所以不能使用 fflush( stdin )来刷新输入缓存。
对于没有定义 fflush( stdin )的编译器,可以使用 fgets()函数来代替它(比用 getchar()、scanf()等函数通用性好)。可以这样忽略输入流中留下的回车等其它输入,从而使下一次的输入总保持一个“干净”的状态。(这个是任何平台下都可以的)
scanf函数读取字符
int main(){ char ch1; char ch2; char ch3; char ch4; scanf(“%c”,&ch1); scanf(“%c”,&ch2); scanf(“%c”,&ch3); scanf(“%c”,&ch4); return 0;}
【分析】用户输入'h'和' '和两个回车符,在监视中可以看到,四个字符如愿以偿得到了用户输入操作的四个字符,也并没有舍弃回车符到缓冲区。
篇6:c语言中的1是什么意思
编译器
GCC,GNU组织开发的开源免费的编译器
MinGW,Windows操作系统下的GCC
Clang,开源的BSD协议的基于LLVM的`编译器
Visual C++:: cl.exe,Microsoft VC++自带的编译器
集成开发环境(IDE)
CodeBlocks,开源免费的C/C++ IDE
CodeLite,开源、跨平台的C/C++集成开发环境
Orwell Dev-C++,可移植的C/C++IDE
C-Free
Light Table
Visual Stdio系列
Hello World
篇7:解析C语言中的sizeof.net
一、sizeof的概念 sizeof是C语言的一种单目操作符,如C语言的其他操作符++、--等,它并不是函数。sizeof操作符以字节形式给出了其操作数的存储大
一、sizeof的概念
sizeof是C语言的一种单目操作符,如C语言的其他操作符++、--等。它并不是函数。sizeof操作符以字节形式给出了其操作数的存储大小。操作数可以是一个表达式或括在括号内的类型名。操作数的存储大小由操作数的类型决定。
二、sizeof的使用方法
1、用于数据类型
sizeof使用形式:sizeof(type)
数据类型必须用括号括住。如sizeof(int)。
2、用于变量
sizeof使用形式:sizeof(var_name)或sizeof var_name
变量名可以不用括号括住。如sizeof (var_name),sizeof var_name等都是正确形式。带括号的用法更普遍,大多数程序员采用这种形式。
注意:sizeof操作符不能用于函数类型,不完全类型或位字段。不完全类型指具有未知存储大小的数据类型,如未知存储大小的数组类型、未知内容的结构或联合类型、void类型等。
如sizeof(max)若此时变量max定义为int max,sizeof(char_v) 若此时char_v定义为char char_v [MAX]且MAX未知,sizeof(void)都不是正确形式。
三、sizeof的结果
sizeof操作符的结果类型是size_t,它在头文件中typedef为unsigned int类型。该类型保证能容纳实现所建立的最大对象的字节大小。
1、若操作数具有类型char、unsigned char或signed char,其结果等于1。
ANSI C正式规定字符类型为1字节。
2、int、unsigned int 、short int、unsigned short 、long int 、unsigned long 、float、double、long double类型的sizeof 在ANSI C中没有具体规定,大小依赖于实现,一般可能分别为2、2、2、2、4、4、4、8、10,
3、当操作数是指针时,sizeof依赖于编译器。例如Microsoft C/C++7.0中,near类指针字节数为2,far、huge类指针字节数为4。一般Unix的指针字节数为4。
4、当操作数具有数组类型时,其结果是数组的总字节数。
5、联合类型操作数的sizeof是其最大字节成员的字节数。结构类型操作数的sizeof是这种类型对象的总字节数,包括任何垫补在内。
让我们看如下结构:
struct a;
在某些机器上sizeof(a)=12,而一般sizeof(char)+ sizeof(double)=9。
这是因为编译器在考虑对齐问题时,在结构中插入空位以控制各成员对象的地址对齐。如double类型的结构成员x要放在被4整除的地址。
6、如果操作数是函数中的数组形参或函数类型的形参,sizeof给出其指针的大小。
四、sizeof与其他操作符的关系
sizeof的优先级为2级,比/、%等3级运算符优先级高。它可以与其他操作符一起组成表达式。如i*sizeof(int);其中i为int类型变量。
五、sizeof的主要用途
1、sizeof操作符的一个主要用途是与存储分配和I/O系统那样的例程进行通信。例如:
void *malloc(size_t size),
size_t fread(void * ptr,size_t size,size_t nmemb,FILE * stream)。
2、sizeof的另一个的主要用途是计算数组中元素的个数。例如:
void * memset(void * s,int c,sizeof(s))。
六、建议
由于操作数的字节数在实现时可能出现变化,建议在涉及到操作数字节大小时用ziseof来代替常量计算。
原文转自:www.ltesting.net
篇8:C语言中的复数C基础
复数:
复数比较详细的内容请参考:复数代数
C支持复数的数学计算,复数Z可以在笛卡尔坐标表示为:Z=x+y*I;其中x和y是实数,I是虚数单位,数x被称为实部,数y为虚部。在c语言中,一个复数是有浮点类型表示的实部和虚部。两部分都具有相同的类型,无论是float,double或者long double。
float _complex:实虚都为float
double _complex:实虚都为double
long double _complex:实虚都为long double
如果在c 源文件中包含了头文件 complex.h ,complex.h定义了complex 和 I宏。宏定义complex和一个关键字_complex 同义。我们可以用complex代替_complex.
下面是个简单的例子,运行在debian 7 (32bit)
代码截图:
运行结果: 详细代码:View Code
creal(x):得到复数的实部(对于 double),如果对于float,使用crealf(x),如果对于long double ,请使用 creall(x)
cimag(x):得到复数的虚部(对于double),如果对于float,使用crealf(x),如果对于long double ,请使用 creall(x)
此外还有一点值得注意的是:
cos(), exp() 和 sqrt()同样也会有对应得复数方法,例如:ccos(),cexp(),csqrt()
本人是个初学者,如果博客中有任何错误或者有更好的技术知识,请多多指教!
篇9:C语言中函数的返回值
如果某个函数从一个地方返回时有返回值,而从另一个地方返回时没有返回值,该函数并不非法,但可能是一种出问题的征兆,”
这句话觉得有些难以理解。
于是写了段测试代码,如下:
#include
int f(int i) {
if (1)
return;
else
return 1;
}
main(void) {
int i = -10;
printf(“%d\n”, f(i));
}
/*
* 本程序用gcc编译没有问题,
* 运行结果如下:
* -10
*/
★ c语言面试题
★ C++笔试经验
★ 联想面试笔试题
【c语言中的堆和栈的区别(共9篇)】相关文章:
“火柴棍式”程序员笔试题2022-05-06
C笔试题及答案2024-01-12
淘宝招聘笔试真题2022-12-03
化工厂招聘笔试真题2022-05-07
名企笔试题2023-06-04
关于面试指南:名企面试题2022-10-22
常见华为面试题2022-12-30
java企业的面试笔试题2022-09-26
名企新型面试题2023-05-20
名企之旅参观策划书2022-05-04