C语言函数弹栈 c语言栈的函数

c语言的 递归函数,是不是这个样子的,弹栈就逐个弹出!是的 。
简单说:
每次调用递归函数:
入栈:为被调函数保存实参、返回地址等信息、分配局部变量空间、并将控制转移到被调函数入口 。
最后一次调用的的递归函数,先出栈,之前调用函数依次出栈 。
出栈:保存当前函数返回值、释放数据空间、并将控制转移到其调用函数 。
C语言函数调用栈程序的执行过程可看作连续的函数调用 。当一个函数执行完毕时C语言函数弹栈,程序要回到调用指令的下一条指令(紧接call指令)处继续执行 。函数调用过程通常使用堆栈实现C语言函数弹栈,每个用户态进程对应一个调用栈结构(call stack) 。编译器使用堆栈传递函数参数、保存返回地址、临时保存寄存器原有值(即函数调用的上下文)以备恢复以及存储本地局部变量 。
不同处理器和编译器的堆栈布局、函数调用方法都可能不同,但堆栈的基本概念是一样的 。
寄存器是处理器加工数据或运行程序的重要载体 , 用于存放程序执行中用到的数据和指令 。因此函数调用栈的实现与处理器寄存器组密切相关 。
AX(AH、AL):累加器 。有些指令约定以AX(或AL)为源或目的寄存器 。输入/输出指令必须通过AX或AL实现,例如:端口地址为43H的内容读入CPU的指令为INAL,43H或INAX,43H 。目的操作数只能是AL/AX,而不能是其C语言函数弹栈他的寄存器 。[5]
BX(BH、BL): 基址寄存器。BX可用作间接寻址的地址寄存器和 基地址寄存器 ,BH、BL可用作8位通用数据寄存器 。[5]
CX(CH、CL):计数寄存器 。CX在循环和串操作中充当计数器 , 指令执行后CX内容自动修改,因此称为计数寄存器 。[5]
DX(DH、DL):数据寄存器 。除用作通用寄存器外,在 I/O指令 中可用作端口 地址寄存器 ,乘除指令中用作辅助累加器 。[5]
2.指针和 变址寄存器
BP( Base Pointer Register):基址指针寄存器 。[5]
SP( Stack Pointer Register): 堆栈指针寄存器。[5]
SI( Source Index Register):源变址寄存器 。[5]
DI( Destination Index Register):目的变址寄存器 。[5]
函数调用栈的典型内存布局如下图所示:
图中给出主调函数(caller)和被调函数(callee)的栈帧布局,"m(雙)"表示以EBP为基地址、偏移量为m字节的内存空间(中的内容) 。该图基于两个假设:第一,函数返回值不是结构体或联合体,否则第一个参数将位于"12(雙)" 处C语言函数弹栈;第二,每个参数都是4字节大小(栈的粒度为4字节) 。在本文后续章节将就参数的传递和大小问题做进一步的探讨 。此外,函数可以没有参数和局部变量,故图中“Argument(参数)”和“Local Variable(局部变量)”不是函数栈帧结构的必需部分 。
其中,主调函数将参数按照调用约定依次入栈(图中为从右到左),然后将指令指针EIP入栈以保存主调函数的返回地址(下一条待执行指令的地址) 。进入被调函数时,被调函数将主调函数的帧基指针EBP入栈,并将主调函数的栈顶指针ESP值赋给被调函数的EBP(作为被调函数的栈底),接着改变ESP值来为函数局部变量预留空间 。此时被调函数帧基指针指向被调函数的栈底 。以该地址为基准,向上(栈底方向)可获取主调函数的返回地址、参数值,向下(栈顶方向)能获取被调函数的局部变量值,而该地址处又存放着上一层主调函数的帧基指针值 。本级调用结束后,将EBP指针值赋给ESP,使ESP再次指向被调函数栈底以释放局部变量;再将已压栈的主调函数帧基指针弹出到EBP , 并弹出返回地址到EIP 。ESP继续上移越过参数,最终回到函数调用前的状态 , 即恢复原来主调函数的栈帧 。如此递归便形成函数调用栈 。
EBP指针在当前函数运行过程中(未调用其C语言函数弹栈他函数时)保持不变 。在函数调用前,ESP指针指向栈顶地址 , 也是栈底地址 。在函数完成现场保护之类的初始化工作后 , ESP会始终指向当前函数栈帧的栈顶 , 此时,若
C语言堆栈中如何 创建 销毁 压栈 弹栈 判空 置空 计数栈(stack)又名堆栈,它是一种运算受限的线性表 。
其限制是仅允许在表的一端进行插入和删除运算 。这一端被称为栈顶,相对地,把另一端称为栈底 。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素 。
这里是C源码,供参考 。
#includeiostream
using namespace std;
const int Max=100;
template class T
class MyStack
{
private:
T *aa;
unsigned int p;
public :
void init();
bool isEmpty();
T pop();
void push(const T a);
unsigned int size();
void destroy();
};
template class T
【C语言函数弹栈 c语言栈的函数】void MyStackT::init()
{
aa = new T[Max 1];
p=0;
return;
};
template class T
bool MyStackT::isEmpty()
{
if(p==0) return true;
elsereturn false;
};
template class T
unsigned int MyStackT::size()
{
return p;
};
template class T
void MyStackT::push(const T a)
{
p=p 1;
aa[p]=a;
};
template class T
T MyStackT::pop()
{
char t=aa[p];
p=p-1;
couttendl;
return t;
};
template class T
void MyStackT::destroy()
{
delete[] aa;
};
int main()
{
MyStackchar st;
st.init();
if(st.isEmpty()) cout"MyStack is empty"endl;
else cout "MyStack is not empty"endl;
st.push('a');
st.push('b');
st.push('c');
st.push('d');
st.push('e');
cout st.size()endl;
while(!st.isEmpty()) st.pop();
st.destroy();
system("pause");
return 0;
}
C语言中函数参数压栈方式为什么是从右到左的因为有些是不定参数的
这样函数内 在处理的时候 从左到右 会更方便 。
根据前面的参数 来确定后面还有多少参数 这样 。
要函数内部弹栈从左到右
那么压栈就只能从右到左了 。
C语言 入栈顺序为什么函数入栈顺序从右往左C语言函数参数入栈顺序从右到左是为了方便可变参数函数 。
一、在函数调用时,函数参数的传递,在C语言中是通过栈数据结构实现的 。
在调用函数时 , 先根据调用函数使用的参数,自右向左依次压入栈中 , 然后调用函数,在函数开始执行时,将参数再依次弹栈 。根据栈数据结构先进后出的特点,在函数中弹栈的顺序就是从左向右的 。
二、对于参数固定的函数,无论是从左向右还是从右向左,都没什么区别,最终都是所有参数全部传递 。
三、对于可变参数,比如printf,会在第一个参数格式字符串中,指明后续有几个参数,各自是什么类型的 。于是在函数中 , 参数格式字符串必须第一个弹栈,否则无法获取参数类型 , 也就无法获知后续参数占几个字节,导致无法正确获知参数 。
四、理论上来说,如果从左向右压栈 , 可变参数标记格式字符串的参数放在最后,那么也是可以的 。不过最早设计C语言的人采用了这种方式 , 后续也就延续下来了 。
C语言栈相关 , 指针操作以及局部变量函数返回的相关问题你这样胡乱提问我也很无奈 。你C语言函数弹栈的代码都没有贴对C语言函数弹栈,所以天知道你的代码是什么 , 假设是如下的代码
#includestdio.h
void
test2(int
*l){
printf("l:%p,*l:%d\r\n",l,*l);
int
mm[10]={1,2,3,4,5,6,7,8,9,10};
printf("mm:%p,l:%p,*l:%d\r\n",mm,l,*l);
int
m=*l;
printf("m:%d\r\n",m);
}
void
test(int**
a){
int
b
=
5;
*a
=
b;
printf("a:%p,*a:%p,a:%d\r\n",a,*a,**a);
}
int
main(void){
int
*
ptr2
=
NULL;
test(ptr2);
int
mm[10]={1,2,3,4,5,6,7,8,9,0};
printf("m:%p,*m:%p,*m:%d\r\n",ptr2,ptr2,*ptr2);
test2(ptr2);
printf("m:%p,*m:%p,**m:%d\r\n",ptr2,ptr2,*ptr2);
return
0;
}
如果不是,那么你自己对照 。
问题1:这个应该是编译器相关的,在我这里,元素11的时候,还是输出5
问题2:你说的对 , 除非新的数据放入堆栈,堆栈当然不会被清空
C语言函数弹栈的介绍就聊到这里吧,感谢你花时间阅读本站内容 , 更多关于c语言栈的函数、C语言函数弹栈的信息别忘了在本站进行查找喔 。

    推荐阅读