壹(变量的作用域及存储方式)
最后更新于:2022-04-01 20:29:57
悟道系列之——C语言
这是我的第一篇博文。对我来说CSDN并不陌生,但一直以来我都是一个默默的潜水者,可是今天我要冒泡了。特意选了十月一日来重新注册账号,我想赋予这个日子以新的意义。在进入正题之前,我想有必要简单的向大家介绍一下自己。
本人80后后,刚毕业于一所普通师范类学校的化学专业。本人形象猥琐,身无长物,自觉难以为祖国的教育事业服务,遂混迹于程序猿们的队伍之中。
本科四年,前半段浑浑噩噩,后半段幡然悔悟。而正式决定踏入编程,则已是2011年的愚人节了。(我有意选择这个日子作为纪念)屈指算来今天竟刚满一年半,这真是一个让人惊喜的巧合。
写了这么多废话,无非是想让大家明白:这不是一个大牛的博客。如果您想从中寻找一些金玉良言,那么让您失望了。这里只是一个技术菜鸟对他一路以来在编程中思考和领悟的记录,分享给那些在学习中有些困惑的初学者。
从C讲起吧,以前学习时做了很多笔记,现在把它们筛选整理成电子版的形式分享出来,也方便自己以后查阅。
本系列文章中的读者应该是 C语言语法的入门者。
因为本文不是零基础扫盲贴。要熟悉C的语法 随便一本教材反复研读实践即可。
此文大多是个人的读书笔记、编程感悟及曾经遇到的问题,至于一些技巧和代码风格网上资源不在少数,故本文很少提及。
提纲:
**壹**:变量的作用域及存储方式
[**贰**:几个关键字、几个运算符、隐式转换/溢出、表达式求值的顺序、左值和右值](http://blog.csdn.net/yang_yulei/article/details/8068210)
[**叁**:数组与指针(一)](http://blog.csdn.net/yang_yulei/article/details/8071047)
[**肆**:数组与指针(二)](http://blog.csdn.net/yang_yulei/article/details/8071068)
[**伍**:字符串、函数、动态内存分配](http://blog.csdn.net/yang_yulei/article/details/8072552)
[**陆**:结构、联合、位段、位级操作](http://blog.csdn.net/yang_yulei/article/details/8072567)
[**柒**:文件、输入输出函数](http://blog.csdn.net/yang_yulei/article/details/8087957)
[**捌**:预处理、程序调试、编程风格](http://blog.csdn.net/yang_yulei/article/details/8098329)
[**玖**:常用库函数](http://blog.csdn.net/yang_yulei/article/details/8098357)
开场白:
**【C语言结合了汇编语言的所有威力和汇编语言的所有易用性】**
壹
**变量的作用域:**
1, 局部变量
局部变量是在函数内定义的变量,其作用域仅限于函数内,在函数内才引用,即可以对它赋值或取值。在作用域外,使用它们是非法的。
2, 全局变量
全局变量是定义在函数之外的变量,它的作用域是从定义处开始,到所在文件的结束。即从定义之处起,它可以在文本的所有函数中使用。
【全局变量的命名最好取有特殊含义的标识符(例如在变量名前加q_)。防止不经意间改变了它的值。***全局变量违反了最低特权原则,而且是糟糕的软件工程方法***】
3, 外部变量
全局变量的作用域是在所在文件的整个文件,而一个文件中的全局变量的作用域还可以扩展到其它文件。某个文件中引用另一个文件中的全局变量,只要用extern声明,说明这个变量是在其它文件中已经定义过的外部变量。那么,该文件中不会为外部变量分配内存。
几点说明:
(1)关于外部变量声明的定义和引用
C所存在的一个众所周知的缺陷是很难区分外部变量声明的定义和引用。(来源于《C语言参考手册》)
标准C:在顶层声明中,如果出现了初始化值,它就被认为是个定义性声明。其它的声明则是引用性声明。在C程序的所有文件中,同一个变量的定义性声明只能出现一次。
~~~
int x ; //引用 (C++认为其是定义)
int x=0; //定义
extern int x ; //引用
extern int x =0 ; //定义 (C++认为非法)
~~~
建议:
A,每个外部变量具有一个单独的定义点(在源文件中)。**在定义性声明中,省略extern类别,并提供一个显式的初始化值: int errcnt = 0 ;**
【所以说,全局变量就是外部变量】
B,在其它引用外部变量的每个源文件或头文件中,**在引用性声明中,使用存储类别extern,并且不要包含初始化值: extern int errcnt ;**
**【注意:】**
**外部变量的引用类型必须和其定义类型一致!**(分别编译的时候编译器无法检查两者类型是否一致,但是若不一致运行时会出错)
~~~
//file1.c------
intarr[80];
//file2.c--------
externint *arr;
intmain()
{
arr[1]= 100;
printf("%d\n",arr[1]);
return0;
}
~~~
该程序可以编译通过,但运行时会出错。原因是,在另一个文件中用 extern int *arr来外部声明一个数组并不能得到实际的期望值,因为他们的类型并不匹配。导致指针实际并没有指向那个数组。修改:extern int arr[]。
数组是数组指针是指针。虽然在函数间传递时数组名会退化为常量指针。在定义的时候它们是不同的,编译器给它们分配不同的空间。在外部声明引用时,编译器见到int*arr只会认为其是指针,由于其是全局变量,故给其初始化为0,而编译器见到extern int arr[]会知道arr为外部定义的数组。
(2)同一源文件中,允许全局变量和局部变量同名,但在局部变量的作用域内,全局变量不起作用。【**即当全局变量与局部变量相遇,局部变量屏蔽全局变量**】
~~~
#include
int a=1 , b=2, c=3 ;
int main(void)
{
{
int a=20, b=30 ;
c=(a-=10)+b++ ;
printf("%d,%d,%d\n",a,b,c) ; //输出10,31,40
}
printf("%d,%d,%d",a,b,c) ; //输出 1,2,40
return0 ;
}
//位于一个花括号之间的所有语句成为一个代码块,在代码块开始位置声明的变量的作用域只在此代码块中
//花括号的作用就是打包,使之成为一个整体,并与外界绝缘。
~~~
**变量的存储方式**
1, 动态存储:在程序的执行过程中,使用它时才分配存储单元,使用完毕立即释放。
(其存储空间在栈上)
自动变量的类型说明符为:auto自动变量是动态存储方式,凡未加存储类型说明的变量均视为自动变量。自动变量的作用域和生存期都局限于定义它的个体内。
2, 静态变量:在变量定义时就分定存储单元并一直保持不变,直至程序结束。
(其存储空间在堆上)
【**静态变量的初值是在编译时赋予的,不是在程序执行期间赋予的**】
(1) 静态局部变量
在局部变量的说明前加上static 就构成静态局部变量。
A,静态局部变量在函数内定义,但**它的生存期为整个程序**。
**B,**其生存期虽为整个程序,但其作用域与自动变量相同,**只能在定义的函数内使用。退出函数后,尽管该变量还在,但已不能再使用。**
C,允许对静态局部变量赋初值。若未赋初值,则由系统自动赋0值
D,只在第一次调用函数时给静态变量赋初值,再次调用定义它的函数时,其保存了前一次被调用后留下的值。
【因此,当多次调用一个函数且要求在调用之后保留某些变量的值时,可采用静态局部变量】
(2) 静态全局变量
在全局变量前加static,就构成了静态的全局变量。它们都是静态存储方式。但两者的区别在于:作用域的扩展上。
全局变量的作用域可以扩展到整个源程序。静态全局变量的作用域局限于一个源文件内。
【因此,全局变量加上static限制,是为了避免在其它源文件中被引用,防止出错】
C语言中static的作用:
1、 修饰变量。
静态全局变量,作用域仅限于变量被定义的文件中。
静态局部变量,在函数体中定义的,就只能在这个函数里用了。
2、 修饰函数。
指函数的作用域仅局限于本文件(内部函数),使用内部函数的好处是防止与其他文件中的函数命名冲突。
';