p是指向局部变量的指针,当函数退出时,局部变量会被释放,这时,p所指向的位置就不一样是原来的数。
创新互联公司是专业的西安网站建设公司,西安接单;提供成都网站制作、网站设计,网页设计,网站设计,建网站,PHP网站建设等专业做网站服务;采用PHP框架,可快速的进行西安网站开发网页制作和功能扩展;专业做搜索引擎喜爱的网站,专业的做网站团队,希望更多企业前来合作!
因为fun()函数返回的值被计算机的临时变量存放,当赋值给p的时候,p是指向临时变量的地址,所以还可以读取出100。
*p = "hello"这是常量字符串,从静态存储区分配,第一步字符串"hello"从静态存储区获取一块内存,指针变量p才指向这块静态内存,这块内存的特点是从程序开始到结束一直从在,所以可以返回。
扩展资料:
函数的返回值类型是在定义函数时指定的。return 语句中表达式的类型应与定义函数时指定的返回值类型一致。如果不一致,则以函数定义时的返回值类型为准,对 return 语句中表达式的类型自动进行转换,然后再将它返回给主调函数使用。
在调用函数时,如果需要从被调函数返回一个值供主调函数使用,那么返回值类型必须定义成非 void 型。此时被调函数中必须包含 return 语句,而且 return 后面必须要有返回值,否则就是语法错误。
参考资料来源:百度百科-返回值
程序的执行过程可看作连续的函数调用。当一个函数执行完毕时,程序要回到调用指令的下一条指令(紧接call指令)处继续执行。函数调用过程通常使用堆栈实现,每个用户态进程对应一个调用栈结构(call stack)。编译器使用堆栈传递函数参数、保存返回地址、临时保存寄存器原有值(即函数调用的上下文)以备恢复以及存储本地局部变量。
不同处理器和编译器的堆栈布局、函数调用方法都可能不同,但堆栈的基本概念是一样的。
寄存器是处理器加工数据或运行程序的重要载体,用于存放程序执行中用到的数据和指令。因此函数调用栈的实现与处理器寄存器组密切相关。
AX(AH、AL):累加器。有些指令约定以AX(或AL)为源或目的寄存器。输入/输出指令必须通过AX或AL实现,例如:端口地址为43H的内容读入CPU的指令为INAL,43H或INAX,43H。目的操作数只能是AL/AX,而不能是其他的寄存器。 [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)"表示以EBP为基地址、偏移量为m字节的内存空间(中的内容)。该图基于两个假设:第一,函数返回值不是结构体或联合体,否则第一个参数将位于"12(%ebp)" 处;第二,每个参数都是4字节大小(栈的粒度为4字节)。在本文后续章节将就参数的传递和大小问题做进一步的探讨。 此外,函数可以没有参数和局部变量,故图中“Argument(参数)”和“Local Variable(局部变量)”不是函数栈帧结构的必需部分。
其中,主调函数将参数按照调用约定依次入栈(图中为从右到左),然后将指令指针EIP入栈以保存主调函数的返回地址(下一条待执行指令的地址)。进入被调函数时,被调函数将主调函数的帧基指针EBP入栈,并将主调函数的栈顶指针ESP值赋给被调函数的EBP(作为被调函数的栈底),接着改变ESP值来为函数局部变量预留空间。此时被调函数帧基指针指向被调函数的栈底。以该地址为基准,向上(栈底方向)可获取主调函数的返回地址、参数值,向下(栈顶方向)能获取被调函数的局部变量值,而该地址处又存放着上一层主调函数的帧基指针值。本级调用结束后,将EBP指针值赋给ESP,使ESP再次指向被调函数栈底以释放局部变量;再将已压栈的主调函数帧基指针弹出到EBP,并弹出返回地址到EIP。ESP继续上移越过参数,最终回到函数调用前的状态,即恢复原来主调函数的栈帧。如此递归便形成函数调用栈。
EBP指针在当前函数运行过程中(未调用其他函数时)保持不变。在函数调用前,ESP指针指向栈顶地址,也是栈底地址。在函数完成现场保护之类的初始化工作后,ESP会始终指向当前函数栈帧的栈顶,此时,若
#includestdio.h
#define stacksize 100 //假定预分配的栈空间最多为100 个元素
typedef char elementtype; //假定栈元素的数据类型为字符 ,在此处可以自行设置
typedef struct
{
elementtype data[stacksize];
int top;
}seqstack;
// 置空栈
void initstack(seqstack *s)
{
s-top=-1;
//解释一下,s-top 指向的是当前栈顶元素的位置
//当要向栈中添加一个新元素时,要先将s-top增加1,
//此时s-top 指向的就是新元素要添加的位置了。
//所以当栈为空时,填加第一元素时,top加1 后
//s-top的值就变为0,也就是第一个元素的位置了。
}
//判栈空
int stackempty(seqstack *s)
{
if(s-top==-1)
return 1; //若相等就返回1,否则为0
else return 0;
}
//入栈
void push(seqstack *s,elementtype x)
{
if(s-top==stacksize -1 ) //进栈前判断栈是否已经满了
printf(" stack overflow\n");
else
{
s-top= s-top + 1;
s-data[s-top]=x;
}
}
//出栈
elementtype pop(seqstack *s)
{
if(stackempty(s)) //出栈前先判断当前栈中是否有内容
printf("stack is empty\n");
else
{
return s-data[s-top--]; //出栈后s-top的值会自减1
}
}
//取栈顶元素(只是想知道栈顶的值,并没有出栈)
elementtype gettop(seqstack *s)
{
if(stackempty(s))
{
printf("stack already empty.\n");
}
else return s-data[s-top];
}
int main()
{
elementtype x;
seqstack *s; //定义一个栈,用指针的方式定义的
initstack(s); //想初始化定义好的栈
//当栈为空时调用出栈操作
pop(s);
//向栈中添加一个元素a
push(s,'a');
//观察此时的栈顶元素
x=gettop(s);
printf("%c\n",x);
//再添加一个元素b
push(s,'b');
//观察此时的栈顶元素
x=gettop(s);
printf("%c\n",x);
//弹出栈顶的元素
x=pop(s);
printf("%c\n",x);
//观察弹出后栈顶元素的变化情况
x=gettop(s);
printf("%c\n",x);
return 0;
}
必须出栈!
aa 和 bb 和c 都是函数内部的局部变量,函数返回后就被释放,也就是在栈中没有了,返回后就剩下图中main()函数所对应的栈结构.
栈只能够通过出栈来减少栈中数据的个数,从反面来讲,如果不出栈,funcA()函数返回后,栈指针还是指向c那,这肯定是不对的,因为函数返回后栈指针就得指向man()的栈结构了。