C语言变量、函数的作用域及变量的存储方式
在C语言中每个变量都有两种基本属性:数据类型、数据的存储类别。
数据类型很多人都已熟知,例如:字符型(char)、整型(int)、浮点型(float)等等。存储类别是指数据在内存中的存储方式,C语言中的存储类别共有4种:自动的(auto)、静态的(static)、寄存器的(register)、外部的(extern)。根据变量的存储类别,可以知道变量的作用域和生存期。
1.自动变量。关键字为auto,但实际上“auto”通常都可以省略,函数中的局部变量如果不用关键字static来定义则都默认为自动类型(auto)的变量,在调用函数时系统会将这些变量分配到内存的动态存储区中,函数调用结束后这些存储空间将被释放。我们平常使用的函数中未用static定义的局部变量都是auto类型。
2.静态变量。关键字为static。静态变量包括全局变量和静态局部变量。全局变量在变量申请时自动存储到内存的静态存储区,即自动申请为静态变量。若希望函数中局部变量的值在函数调用结束后不消失,则需要用关键字static将该局部变量声明为静态局部变量,这些变量也被存储在内存的静态存储区。加上关键字static修饰后,原来的局部变量就类似于全局变量,它的值在下次调用该函数之前不会发生改变;与全局变量不同的是,全局变量的值可以在程序中的任何部分进行修改,而静态局部变量在程序中的其他部分是不可见的。为了说明关键字static的作用,举例如下:
#include<stdio.h>
void add()
{
static int n=0;//申请静态变量n,对其赋初值操作仅仅在编译函数时进行一次
printf("n = %d\n",n);
n++;
}
int main(void)
{
add();
add();
add();
}
运行结果:
n = 0
n = 1
n = 2
通过以上讨论,得出理解静态局部变量的几个要点:
(1)静态局部变量存储在内存的静态存储区。
(2)对静态局部变量赋初值是在编译时进行的,即仅赋值一次。如果定义静态局部变量时不赋初值,则编译器将自动对其赋初值0(对数值型变量)或空字符(对字符型变量)。
(3)静态局部变量的值在函数调用结束后不发生改变,但在程序中的其他部分是不可见的。
静态局部变量的缺点:
(1)需要多占用系统的内存。
(2)降低程序的可读性。当调用函数次数较多时,可能会分不清静态局部变量的当前值是什么。
因此,在非必要场合应减少使用静态局部变量。
3.寄存器变量。关键字register。变量的值一般是存储在计算机的内存中的,但对于一些频繁调用的变量,为了减少变量的调用时间可将其存在CPU的寄存器中,定义这样的变量需要使用关键字register。需要说明的是,现在优化的编译器能够识别使用频繁的变量,从而自动将其放入CPU的寄存器中,因此需要程序员使用register关键字来定义寄存器变量的场合较少。
4.外部变量。外部变量是在函数外部定义的全局变量。关键字“extern”主要用来扩展外部变量的作用域。通常来说,外部变量的生存周期为程序的整个运行过程,它的作用域从定义该变量处到本程序文件的末尾,在此范围内该变量都是可见的。但是如果需要扩展外部变量的作用范围,就需要用到关键字extern。有以下两种扩展外部变量的情况:
(1)在一个文件内扩展外部变量的作用域。外部变量的作用域从定义该变量处到本程序文件的末尾,如果需要在定义之前使用该外部变量,应在使用之前用extern对该变量进行外部变量声明。例如:
#include<stdio.h>
extern int a;//外部变量声明
void output()
{
printf("a=%d\n",a);
}
int a =3;
int main(void)
{
output();
return 0;
}
如果程序中没有声明语句“extern int a;”则编译时会报错,因为变量output()函数中的变量a未定义就使用。
(2)将外部变量的作用域扩展到其他文件。如果在本文件中定义的变量希望能用于其他文件,则可以在需要用到该变量的文件开头加入外部变量声明。例如
//文件auto1.c
#include<stdio.h>
extern int a;
void output()
{
printf("a=%d\n",a);
}
int main(void)
{
output();
return 0;
}
//文件auto2.c
int a = 1000;
文件auto1.c中的声明语句“extern int a;”是告诉编译器:int型变量已经在其他文件中定义。
关键字“static”可用来限定外部变量的使用范围。如果某些外部变量只希望在本文件中使用,禁止在该文件以外的地方引用,可以在定义时在该变量前加关键字static,在前面的例子中如果将文件auto2.c改为:
//文件auto2.c
static int a = 1000;
则编译时会出错,因为文件auto1.c中的a成了未定义的变量。
小结:static声明一个变量的作用是(1)局部变量用static声明,该变量将被存入静态存储区,该变量在程序执行期间不释放。(2)全局变量用static声明,该变量的作用域被限定在本文件,即用static声明的全局变量仅在当前文件可见。
二.函数的作用域
C语言中的函数根据能否被其他源文件调用分为内部函数和外部函数。
只能被本文件中其他函数调用的函数称为内部函数,内部函数也称为静态函数,用关键字static来声明。例如:
static int fun(int a);
声明了一个内部函数fun(int a),该函数只能在本文件中可见。通常把只能由本文件使用的函数和外部变量放在本文件的开头用static声明,可以防止其他文件误调用,提高程序可靠性。这在多人合作编写的大型程序中非常有用。
可供其他文件调用的函数称为外部函数,用关键字extern来声明。例如
extern int fun(int a)
{
…
}
定义了一个外部函数。c语言中的函数默认为外部函数,因此函数定义时省略关键字extern则默认为外部函数。应注意的是:调用已经在其他文件中定义过的外部函数时,当前文件的开头需要加上被调用函数的extern声明,旨在告诉编译器:该函数已经在其他文件中定义过了。例如:
//文件extern1.c
#include <stdio.h>
extern int a ;
extern int sum(int x,int y);
int main(void)
{
a = sum(2,3);
printf("The sum is %d",a);
}
//文件extern2.c
int a = 8;
int sum(int x,int y)
{
return (x+y);
}
文件extern1.c中“extern int sum(int x,int y);”语句声明sum()函数是已经在其他文件中定义过的函数,若没有该语句,编译器将报错:sum函数未定义就使用。
三.static、extern、auto的用法小结
关键字static和关键字extern在声明函数和全局变量时有某种“互补性”。
用关键字static声明定义的函数和全局变量作用域仅在当前文件,对其他文件不可见,不能被本文件以外的文件引用。函数和全局变量使用static声明,可以防止误操作。
用关键字extern声明定义的函数和全局变量可以在本文件以外的使用,但使用时必须在使用文件的前面加上该函数或全局变量的extern声明。另外,默认的函数、全局变量均为extern类型,故定义其他文件可以使用的函数和全局变量时可省略extern声明。
关键字static和关键字auto在声明定义局部变量时有某种“互补性”。
用static声明定义的局部变量将被存入静态存储区,该变量在程序执行期间不释放,这种用法比较少见。
用auto声明定义的局部变量将被存入动态存储区,每次函数调用结束后该内存空间就被释放,下次使用该变量时需要重新申请内存空间,重新赋初值,常见的局部变量均属这种类型,关键字auto可省略。
参考文献:《C语言程序设计》 第2版 谭浩强 清华大学出版社
C语言变量、函数的作用域及变量的存储方式的更多相关文章
- JavaScript基础03——函数的作用域及变量提升
1.作用域 作用域,变量在函数内部作用的范围/区域.有函数的地方就有作用域. 2.局部作用域和全局作用域 function fn(){ var a = 1; } console.log(a); / ...
- go语言基础之不同作用域同名变量
1.不同作用域同名变量 示例: package main import "fmt" var a byte //全局变量 func main() { var a int //局部变量 ...
- C变量类型和作用域
C语言中所有变量都有自己的作用域,申明变量的类型不同,其作用域也不同.C语言中的变量,按照作用域的范围可分为两种, 即局部变量和全局变量. 一.局部变量 局部变量也称为内部变量.局部变量是在函数内作定 ...
- php基础知识【函数】(8)xml和变量函数
一.XML函数 参数类型 data --string,需要解析的数据集. parser --resource,一个指向要取得字节索引的 XML 解析器的引用. 1.创建和释放XMl解析器 ...
- 分享:Oracle 系统变量函数用法说明
在Oracle数据库中,Oracle系统变量函数是经常会使用到的函数,分享下Oracle系统变量函数的用法. Oracle函数多种多样,系统变量函数就是其中之一,介绍三种最常见的系统变量函数. Ora ...
- javascript 函数和作用域(函数,this)(六)
重点. 一.函数 1.函数介绍 函数是一块JavaScript代码,被定义一次,但可执行和调用多次.JS中的函数也是对象,所以JS函数可以像其他对象那样操作和传递,所以我们也常叫JS中的函数为函数对象 ...
- c++变量的存储方式
1.名字的作用域 作用域是从空间的角度来分析的,c++的作用域以花括号分隔,定于于所有{ }以外的名字具有全局作用域,定义于{ }以内的名字具有块作用域 2.变量的生命周期 生命周期是从变量存在的时间 ...
- C语言中变量和函数的作用域和链接属性
C语言中变量和函数的作用域和链接属性 作用域 代码块作用域: 代码块指的是使用"{}"包围起来的部分. 在代码块中定义的变量,代码块之外是不能访问的. 代码块嵌套之后的变量作用域, ...
- JavaScript变量的作用域和函数的作用域的区别
变量作用域和函数作用域都涉及到变量值的变化,本文旨在让大家明白他们之间的区别 变量的作用域: 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接 ...
随机推荐
- 【cs231n】线性分类笔记
前言 首先声明,以下内容绝大部分转自知乎智能单元,他们将官方学习笔记进行了很专业的翻译,在此我会直接copy他们翻译的笔记,有些地方会用红字写自己的笔记,本文只是作为自己的学习笔记.本文内容官网链接: ...
- geoserver源码学习与扩展——增加服务接口
参看:http://www.cnblogs.com/sillyemperor/archive/2011/01/11/1929420.html 上文写的很详细了.
- location的部分属性
http://www.w3school.com.cn/jsref/dom_obj_location.asp location.host 可以设置或返回主机名和当前url的端口 www.w3sch ...
- Codeforces Round #360 (Div. 2) D. Remainders Game
D. Remainders Game time limit per test 1 second memory limit per test 256 megabytes input standard i ...
- 使用cxf调用webservice
1.引入maven包 <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt ...
- ADO.net笔记
1.DbConnectionConnection对象也称为数据库连接对象,Connection对象的功能是负责对数据源的连接.所有Connection对象的基类都是DbConnection类.Conn ...
- 【Python】常用排序算法的python实现和性能分析
作者:waterxi 原文链接 背景 一年一度的换工作高峰又到了,HR大概每天都塞几份简历过来,基本上一天安排两个面试的话,当天就只能加班干活了.趁着面试别人的机会,自己也把一些基础算法和一些面试题整 ...
- getline
istream& istream::getline(char*, streamsize,char= '\n'); 函数getline与get的区别在于,函数get当遇到分隔符后,停止获取,并将 ...
- Educational Codeforces Round 42 (Rated for Div. 2)F - Simple Cycles Edges
http://codeforces.com/contest/962/problem/F 求没有被两个及以上的简单环包含的边 解法:双联通求割顶,在bcc中看这是不是一个简单环,是的话把整个bcc的环加 ...
- poj1679次小生成树入门题
次小生成树求法:例如求最小生成树用到了 1.2.4这三条边,总共5条边,那循环3次的时候,每次分别不用1.2.4求得最小生成树的MST,最小的MST即为次小生成树 如下代码maxx即求最小生成树时求得 ...