return
#include<stdio.h>
char* show(){
char str[] = "hello world";
return str;
}
int main(){
char *ch = show();
printf("%s\n", ch);
return 0;
}
我们先看一下这个代码,这个代码是有问题的,大家可能都能知道,str数组,在show函数里面定义,是局部变量,出了作用域会销毁,所以打印乱码,但是知道这一点还是太浅显了,接下来讲一些干货!!!!!!! **先问两个问题:
1.C语言中有字符串和字符串类型吗?
C语言中没有字符串类型但是有字符串,定义一个字符串可以利用指针,或者数组,字符串的末尾是以反斜杠0结尾,不作为字符串的一部分,只是作为一个结束标识符要明确,求字符串长度和大小是不一样的,求字符串的长度是不包含反斜杠0的,求字符串的大小是本质就是求在这字符串占用几个字节空间,所以要加上反斜杠0.
2.我们平常删除数据,比如说删除一部电影是真的在内存中删除了吗
在计算机中删除一个数据就是清空为0/1吗? 不是的,比如说:我们下载一部电影3个G,需要5分钟,但是你删除的时候,2~3秒就删除了呢 其实计算机删除数据只要把个数据,设置为无效就欧克了 ,可能是通过一些协议啥的,这样设置完之后,你就可以再次利用这块空间,进行写入。
接下我们在栈帧方面解释上面那个代码
现在我们谈一个问题:函数调用会开辟栈帧,函数中的变量,会在栈帧中开辟空间,问题来了,你咋确保你开辟的栈帧,一定够函数中变量开辟空间用呢
解释:我们函数中变量定义肯定是有类型的这是毋庸置疑的,我们的程序没有运行之前,编译器就会根据我们的类型来预估最少开辟多大的空间,根据这个预估,编译器就会合理的开辟出我们所需要的空间 这也体现了我们关键字的作用,就是告诉编译器我需要多大的空间
经过上面的学习我们就可以理解一下递归的问题了
递归在没有出口的时候,函数就会重复的被调用,每次调用的也没释放,就会在栈空间连续的向下放,最后就会发生栈溢出
为什么临时变量具有临时性?
大家都知道了,函数调用形成栈帧,返回函数释放栈帧,C语言中的变量大部分都是在函数中定义的,就说明是局部变量,除了static修饰的。 函数调用,栈帧就开辟,该函数里的变量,就会在栈帧中开辟自己的空间,函数返回,栈帧释放,栈帧都释放了,在该栈帧中定义的变量,肯定也被释放了呗,好比,宇宙都毁灭了,还会有星球吗
言归正传继续讲解return
我们看着个代码,经过上面所说函数调用形成栈帧,函数返回,释放栈帧,哪这个GetData函数,为啥还可以返回x值呢??? 解释: 直接查看反汇编 F10直接进去 接着返回主函数
从这我们可以明白,我们之前理解的没错,函数返回就是释放栈帧,x的值为啥能返回来是因为:函数的返回值是通过,寄存器的方式,返回函数调用方的!!!
------------------------------------------------------------------------------------------------ 我们如果要是不接收函数的返回值会怎末样呢? 继续反汇编
在返回主函数
总结:函数的返回值是通过寄存器的方式返回调用方的; 如果函数的返回值没有被接收的,被调函数还是会把返回值放到寄存器;
---------------------------------------------------------------------------------------------
const
const修饰的变量是不能直接修改的,是可以间接修改的 const修饰的变量可以间接的被修改,那const的意义何在呢
1,const修饰的变量,并非是,不可修改的常量 2,const修饰变量是给编译器看的,告诉编译器,这个变量是不可以修改的,如果有人修改了,你就直接报错 3,const修饰的变量是给兄弟们看的,告诉兄弟们,这个变量不要改 看一个真的不能修改的
如果编译器对const报错是在编译的时候报错的,不是在运行之后报错的, const修饰变量就是给编译器看的
const修饰出数组
const修饰的数组,数组的每个元素都不能被修改
const修饰指针
在此我们先谈一下指针!!!
指针变量和指针是一个概念吗?
指针
简单说一下指针是什么为啥要有呢? 我们都住过宿舍,每个宿舍都有门牌号吧,这就是个标识,能告诉别人,你住在那个屋子里面。 指针也是对每个内存单元的一个标识,这样在使用这块空间的时候,才能找到。换句话说其实指针就是地址。 为啥要有指针是为了提高查找效率。如果没有指针还有遍历整个内存找数据吗?如果没有门牌号找人还要搜查整个宿舍楼吗
指针变量
指针变量,是变量呀,指针就是数据呀,是数据就可以被存放呀,所以指针变量就是用来存放指针相关数据的变量,在32位平台,4字节,在64位平台,8字节
左值与右值
任何变量名在不同的场景中代表不同的含义!!! 指针也是一样的
第7行指针变量p在这代表的是p的空间,存放的是b的地址。 第8行指针变量p代表的是p空间里面的内容,即b的地址,存到指针变量q中
解引用
(类型相同)对指针进行解引用,代表指针所指向的目标 p指向a,解引用p,就是a!!!
言归正传const修饰指针
第一种
#include<stdio.h>
int main(){
int a = 10;
const int *p = &a;
*p = 100;
p = 100;
return 0;
}
第二种
#include<stdio.h>
int main(){
int a = 10;
int const *p = &a;
*p = 100;
p = 100;
return 0;
}
第三种
#include<stdio.h>
int main(){
int a = 10;
int * const p = &a;
*p = 100;
p = 100;
return 0;
}
第四种
#include<stdio.h>
int main(){
int a = 10;
int const * const p = &a;
*p = 100;
p = 100;
return 0;
我们再看两种情况!!! 第一种: 第二种: ------------------------------------------------------------------------------------------
const修饰函数参数
void show(const int *_p){
printf("%d\n", *_p);
}
int main(){
int a = 10;
int*p = &a;
show(p);
return 0;
}
临时拷贝的知识点
函数调用时,会形成一份临时拷贝,那么参数要是指针变量呢,会形成临时拷贝吗?
答案是也会形成临时拷贝,指针变量也是变量呀,里面存放的是地址,地址也是数据呀,是数据就要形成临时拷贝呀 C中,任何函数参数都一定要形成临时变量,包括指针变量
const修饰返回值
volatile
首先要明确,在没有加volatile的代码,默认会被优化,加上就不会被优化。 大概解释一下: 不加volatile
#include <stdio.h>
int pass = 1;
int main()
{
while(pass){
}
return 0;
}
加volatile
#include <stdio.h>
volatile int pass = 1;
int main()
{
while(pass){
}
return 0;
}
结论: volatile 忽略编译器的优化,保持内存可见性 其他问题:
const volatile int a = 10; 在vs2013和gcc 4.8中都能编译通过 const是在编译期间起效果 volatile在编译期间主要影响编译器,形成不优化的代码,进而影响运行,故:编译和运行都起效果。 const要求你不要进行写入就可以。volatile意思是你读取的时候,每次都要从内存读。两者并不冲突。 虽然volatile就叫做易变关键字,但这里仅仅是描述它修饰的变量可能会变化,要编译器注意,并不是它要求对应变量必须变化!这点要特别注意
完结
|