Static Variable

Static and Global Variables

Variables that are defined outside functions are loosely called global variables.  They are called global variables, as they can be accessed from any module of yourproject.  For instance, in the following project consists of two files: One.c andTwo.c.  The contents of both files are given in the following table.

//Box #1: One.c

int GCounter=0;  // Define a global variable

int GetCount(void)  // Define a function GetCount
	{
	return ++GCount;
	}

//Box #2: Two.c

#include <stdio.h>

extern int GCount; // Declare the variable
int GetCount(void); // Declare the function GetCount

int main(void)
	{
	GCount=100;
	printf("Count=%d\n",GetCount() );
	return 0;
	}

The variable GCount is a global variable defined in the file One.c.  To access thevariable GCount from the two.c file, we declare the variable by prefixing the declarationwith the C keyword extern.  When ever a variable declaration, ismade with prefix extern,  the compiler knows that a variable doesexists somewhere in your project. The C linker binds all of the object files generated inyour project and assures that all references are made correctly.  Before execution ofyour project, GCounter is initialized with a value of zero.  In the main function,the variable is then set to 100.  When GetCount() is called, the GCount is increasesto 101.  So the output is:  Count=101.

When a variable is defined as static outside any function, it can not be accessibleoutside the current file as are global variables.  Box #3 contains an example of astatic declared variable.

//Box #3: Static Variable
static int GCounter=0;

int GetCount(void)
	{
	return ++GCount;
	}

The prefix static is used to define functions too. In both cases, thefunctions and variables are only accessible in the current file.  Static definedvariables and functions are called File Scope Functions and Variables.

Static defined variables and functions offer C programmers the ability to provide aprimitive form of encapsulationEncapsulation isa method by which a complex module hides its inner working functions and variables.  Imagine a television with an on/off switch.  The internal workings are hidden andprotected from the end user via the television cover.  The television cover ensuresthat some one does not play with the internals of the television and destroy the properfunctioning of the device. Similarly, the encapsulation offers protection to the module toinsure proper functioning.

In the next example,  an accumulator module is used to accrue the sum of severalnumbers.  Notice that the module has several functions that are accessible outsidethe module.  But, a single variable GTotal is declared static.  It is encapsulated (hidden) inside the module.

// Accum.h - Header file for Module Accum
#ifndef Accum_h
#define Accum_h

void AccumClear(void);  // Clear the Accumulator
void AccumAdd(int val); // Increase Accumulator
int AccumGet(void);  // Return current Accumulated value

#endif Accum_h
// Accum.c  - Implementation of Module Accum

#include "Accum.h"

///
static int GTotal=0;  // Static variable(private to module)

//
void AccumClear(void)  // Clear the Accumulator
	{
	
	}

//
void AccumAdd(int val) // Increase Accumulator
	{
	GTotal += val;
	}

//
int AccumGet(void)  // Return current Accumulated value
	{
	return GTotal;
	}

// main.c Example usage of module Accum
// Program will find the sum 1+...+100
#include "Accum.h"

int main(void)
	{  int i;
	AccumClear();  // Clear Accum
	for(i=1;i<=100;++i)
		{  AccumAdd(i);  }
	printf("Total = %d\n",AccumGet() );
	}

If any one attempts to get access to the variable GTotal by creating adeclaration extern int GTotal, the linker will complain that there is nosuch variable.  The statically declared GTotal is completely hiddenfrom the linker.

Static can also be used in functions.  The Next example demonstrates a bubblesort.  Notice that we need a support function Bubble that isdeclared as static.  It can not be accessed outside the current file.

// BubbleSort Module - BubbleSort.h
#ifndef BubbleSort_h
#define BubbleSort_h

void BubbleSort(int ar[],int n);

#endif BubbleSort_h
// BubbleSort Module - BubbleSort.c
#include "BubbleSort.h"

//
static void Bubble(int ar[],int n); // bubbles largest element to one side

//
void BubbleSort(int ar[],int n)
	{	int i;
	for(i=n;i>0;--i)
		{  Bubble(ar,i);  }
	}

//
static void Bubble(int ar[],int n)
	{	int i;
	for(i=0;i<n-1;++i)
		{
		if(ar[i]>ar[i+1])
			{  int tmp;
			tmp=ar[i]; ar[i]=ar[i+1]; ar[i+1]=tmp;
			}
		}
	}
#include <stdio.h>
#include "Bubble.h"

int main(void)
	{  int ar[]={4,6,4,2,5,7,8,5,3,2,4,6,7};  int i;
	BubbleSort(ar,sizeof(ar)/sizeof(int));
	for(i=0;i<sizeof(ar)/sizeof(int);++i)
		{  printf("%d ",ar[i]);  }
	return 0;
	}

Static variable

From Wikipedia, the free encyclopedia

In computer programming, a static variable is a variable that has been allocated statically—whose lifetime or "extent" extends across the entire run of the program. This is in contrast to the more ephemeralautomatic variables (local variables are generally automatic), whose storage is allocated and deallocated on thecall stack; and in contrast to objects whose storage is dynamically allocated in heap memory.

When the program (executable or library) is loaded into memory, static variables are stored in the data segment of the program's address space (if initialized), or the BSS segment (if uninitialized), and are stored in corresponding sections of object files prior to loading.

The static keyword is used in C and related languages both for static variables and other concepts.

Scope

In terms of scope and extent, static variables have extent the entire run of the program, but may have more limitedscope. A basic distinction is between a static global variable, which has global scope and thus is in context throughout the program, and astatic local variable, which has local scope. A static local variable is different from local variable. It is initialized only once no matter how many times that function in which it resides is called. It may be used as a count variable. A static variable may also havemodule scope or some variant, such as internal linkage in C, which is a form of file scope or module scope.

In object-oriented programming, there is also the concept of a static member variable, which is a "class variable" of a statically defined class – a member variable of a given class which is shared across all instances (objects), and is accessible as a member variable of these objects. Note however that a class variable of a dynamically defined class, in languages where classes can be defined at run time, is allocated when the class is defined and is not static.

Example

An example of static local variable in C:

#include <stdio.h>

void func() {
	static int x = 0; 
	/* x is initialized only once across five calls of func() and
	  the variable will get incremented five 
	  times after these calls. The final value of x will be 5. */
	x++;
	printf("%d\n", x); // outputs the value of x
}

int main() { //int argc, char *argv[] inside the main is optional in the particular program
	func(); // prints 1
	func(); // prints 2
	func(); // prints 3
	func(); // prints 4
	func(); // prints 5
        return 0;
}

See also

References



学习C语言时已了解全局变量,它能够实现数据共享。如果在一个程序文件中有多个函数,在每一个函数中都可以改变全局变量的值,全局变量的值为各函数共享。但是用全局变量时安全性得不到保证,由于在各处都可以自由地修改全局变量的值,很有可能偶一失误,全局变量的值就被修改,导致程序的失败。因此在实际工作中很少使用全局变量。如果想在同类的多个对象之间实现数据共享,也不要用全局对象,可以用静态的数据成员。

1、静态数据成员

静态数据成员是一种特殊的数据成员。它以关键字static开头。

静态数据成员定义一般形式:
static 
数据类形静态数据成员

静态数据成员赋值一般形式:
数据类型类名::静态数据成员名=初值;//只能在类体外进行初始化。

静态数据成员引用一般形式:
类名::静态数据成员名 // 通过类名引用静态数据成员
对象.静态数据成员名 //通过对象名引用静态数据成员

例:
class Box
{public

int volume()

private

static int height
//height定义为静态的数据成员
int width

int length
 }

10 引用静态数据成员。
#include <iostream>
using namespace std;

class Box
{public:
Box(int,int);
int volume();
static int height; //
height定义为公用的静态的数据成员
int width;
int length; };

Box::Box(int w,int len) 
//
通过构造函数对widthlength赋初值
{width=w;
length=len; }
int Box::volume() 
{return(height*width*length); }
int Box::height=10;
//
对静态数据成员height初始化

int main()
{Box a(15,20),b(20,30);
cout<<a.height<<endl; //
通过对象名a引用静态数据成员
cout<<b.height<<endl; //
通过对象名b引用静态数据成员
cout<<Box::height<<endl; //
通过类名引用静态数据成员
cout<<a.volume()<<endl; //
调用volume函数,计算体积,输出结果
return 0; }

说明:
(1)
如果只声明了类而未定义对象,则类的一般数据成员是不占内存空间的,只有在定义对象时,才为对象的数据成员分配空间。静态数据成员不属于某一个对象,在为对象所分配的空间中不包括静态数据成员所占的空间。静态数据成员是在所有对象之外单独开辟空间。只要在类中定义了静态数据成员,即使不定义对象,也为静态数据成员分配空间,它可以被引用。
在一个类中可以有一个或多个静态数据成员,所有的对象共享这些静态数据成员,都可以引用它。
(2)
静态数据成员不随对象的建立而分配空间,也不随对象的撤销而释放(一般数据成员是在对象建立时分配空间,在对象撤销时释放)。静态数据成员是在程序编译时被分配空间的,到程序结束时才释放空间。
(3)
静态数据成员可以初始化,但只能在类体外进行初始化
注意:不能用参数初始化表对静态数据成员初始化。如在定义Box类中这样定义构造函数是错误的:
Box(int h
int wint len)
height(h){} //错误,height是静态数据成员如果未对静态数据成员赋初值,则编译系统会自动赋予初值0
(4)
静态数据成员既可以通过对象名引用,也可以通过类名来引用
注意:在上面的程序中将height定义为公用的静态数据成员,所以在类外可以直接引用,可以看到在类外可以通过对象名引用公用的静态数据成员,也可以通过类名引用静态数据成员
如上例中:a.height//通过对象名a引用静态数据成员。
Box:: height//
通过

如果静态数据成员被定义为私有的,则不能在类外直接引用,而必须通过公用的成员函数引用。
(5)
有了静态数据成员,各对象之间的数据有了沟通的渠道,实现数据共享,因此可以不使用全局变量。全局变量破坏了封装的原则,不符合面向对象程序的要求。
(6)
公用静态数据成员与全局变量的不同,静态数据成员的作用域只限于定义该类的作用域内(如果在一个函数中定义类,那么其中静态数据成员的作用域就是此函数内)。在此作用域内,可以通过类名和域运算符"::"引用静态数据成员,而不论类对象是否存在。

2静态成员函数

静态成员函数定义一般形式:
static 
数据类型静态成员函数

静态数据成员函数引用一般形式:
类名::静态函数成员名// 通过类名引用静态数据成员
对象.静态函数成员名 //通过对象名引用静态数据成员

作用:
与静态数据成员不同,静态成员函数的作用不是为了对象之间的沟通,而是为了能处理静态数据成员。

静态成员函数与非静态成员函数的根本区别是
非静态成员函数有this指针,而静态成员函数没有this指针。由此决定了静态成员函数不能访问本类中的非静态成员数据。

说明:
静态成员函数可以直接引用本类中的静态数据成员,因为静态数据成员同样是属于类的,可以直接引用。在程序中,静态成员函数主要用来访问静态数据成员,而不访问非静态成员。并不是绝对不能引用本类中的非静态成员,只是不能进行默认访问,因为无法知道应该去找哪个对象。如果一定要引用本类的非静态成员,应该加对象名和成员运算符"."


11 静态成员函数的应用。
#include <iostream>
using namespace std;
class Student
 //
定义Student
{public:
Student(int,int,int); //
定义构造函数
void total();
static float average(); //
声明静态成员函数
private:
int num;
int age;
float score;
static float sum; //
静态数据成员
static int count;}; //
静态数据成员

Student::Student(int m,int a,int s)
{num=m;
age=a;
score=s; }

void Student::total() 
//
定义非静态成员函数
{ sum+=score; //
累加总分
count++; } //
计已统计的人数 


Static float Student::average() //
定义静态成员函数
{ return(sum/count); }
 //
使用静态数据成员

float Student::sum=0; //对公用静态数据成员初始化
int Student::count=0;
 //
对公用静态数据成员初始化

int main()
{Student stud[3]={ //
定义对象数组并初始化
Student(1001,18,70),
Student(1002,19,79),
Student(1005,20,98) };
int n;
cout<<"please input the number of students:";
cin>>n; //
输入需要求前面多少名学生的平均成绩
for(int i=0;i<n;i++) //
调用ntotal函数
stud[i].total();
cout<<"The average score of "<<n<<" students is "<<stud[0].average()<<endl;//
使用对象名调用静态成员函数,也可通过类名调用:Student::average()
return 0; }

运行结果为
please inputthe numberOfstudents
3/
the average score of3 students is 82.3333

说明:
(1)
在主函数中定义了stud对象数组,为了使程序简练,只定义它含3个元素,分别存放3个学生的数据(每个学生的数据包括学号、年龄和成绩)。程序的作用是先求用户指定的n名学生的总分,然后求平均成绩(n由用户输入)
(2)
Student类中定义了两个静态数据成员sum(总分)count(累计需要统汁的学生人数),这是由于这两个数据成员的值是需要进行累加的,它们并不是只属于某一个对象元素,而是由各对象元素共享的,可以看出:它们的值是在不断变化的,而且无论对哪个对象元素而言,都是相同的,而且始终不释放内存空间。
(3)total
是公有的成员函数,其作用是将一个学生的成绩累加到snm中。公有的成员函数可以引用本对象中的一般数据成员(非静态数据成员),也可以引用类中的静态数据成员。score是非静态数据成员,sumcount是静态数据成员。
(4)average
是静态成员函数,它可以直接引用私有的静态数据成员(不必加类名或对象名),函数返回成绩的平均值
(5)
main函数中,引用total函数要加对象名(今用对象数组元素名),引用静态成员函数average函数要用类名或对象名。
(6)
请思考:如果不将average函数定义为静态成员函数行不行?程序能否通过编译?需要作什么修改?为什么要用静态成员函数?请分析其理由。
(7)
如果想在average函数中引用stud[l]的非静态数据成员score,应该怎样处理?
有人在上面的程序基础上将静态成员函数average改写为
float Student::average() //
定义静态成员函数
{cout<<stud[1]
score<<endl //引用非静态数据成员
return(sum/count)
}
结果发现在编译时出错。可以将average函数的定义改为

floatStudent::average(Studentstu) //
函数参数为对象
{cout<<stu.score<<endl
//通过对象名引用非静态数据成员
return(sum/count)

以上是在例11基础上顺便说明静态成员函数引用非静态数据成员的方法,以帮助理解。但是在程序中最好养成这样的习惯:只用静态成员函数引用静态数据成员,而不引用非静态数据成员。这样思路清晰,逻辑清楚,不易出错。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值