详解关键字static,const,volatile

static

static修饰局部变量

static修饰局部变量用于修改变量的存储位置,从自动变量修改为静态变量(在静态区开辟空间,不在栈上开辟),但变量的链接属性和作用域不受影响。static修饰局部变量时该变量在程序执行之前创建,并在程序的整个执行空间一直存在,即使出了作用域也只是被隐藏并不销毁该变量。请看下面的两段代码

代码一:没有static修饰的局部变量

int main()
{
	int i=0;
	for(i=0;i<10;i++)
	{
		int j=10;
		j+=1;
		printf("%d ",j);   //没有static修饰的j每次都是10
	}
	system("pause");
	return 0;
}

代码二:static修饰的局部变量

int main()
{
	int i=0;
	for(i=0;i<10;i++)
	{
		static int j=10;
		j+=1;
		printf("%d ",j);   //有static修饰的j每次都是上一次+1之后的值
	}
	system("pause");
	return 0;
}

从上面两段代码可以看出static修饰局部变量确实改变了变量的存储位置,存储在静态区上,出了作用域也未被销毁,所以代码二的j每次都是加1之后的值

static修饰全局变量和函数

static修饰函数和全局变量时用于修改变量的链接属性,由extern变为internal,但是变量的存储类型和作用域不受影响,且static修饰的全局变量只能在他们的源文件中访问,即使外部文件使用extern也无法访问

好了static的基础介绍就到这里了,下面让我们来看一道关于static的例题吧

int count=3;
int main()
{
	int i=0,sum=0,count=2;
	for(i=0,sum=0;i<count;i+=2,count++)
	{
		static int count=4;
		count++;
		if(i%2 == 0)
		{
			extern int count;
			count++;
			sum+=count;
		}
		sum+=count;
	}
	printf("%d %d\n",count,sum);   //4  20
	system("pause");
	return 0;
}

刚一看到这道题是不是有点晕呢?确实刚开始的时候我也觉得有点害怕,因为里面存在三种不同存储方式的变量count:全局的,局部的,静态的,关键是它还时不时的使用一下count这就容易让人搞不清楚到底每次使用的时候调用的是哪一个count,不过不用怕,让我们来慢慢分析

注意:

1).当局部变量和全局变量冲突的时候,局部变量优先,当全局的count和局部的count同时出现时优先考虑局部的变量count

2).extern声明变量使该变量具有外部链接属性

3).static修饰局部变量(不销毁该变量出作用域被隐藏)

const

为什仫要存在const关键字?以及const可以修饰什仫?用const修饰有什仫与众不同的地方?下文主要就这三个问题予以讨论。

要解决第一个问题就得了解define定义的宏和标识符了,详情请见下面链接

http://blog.csdn.net/qq_34328833/article/details/52144447

大概了解了define定义的标识符和宏之后,我们就会发现由define定义的宏的很多缺点:宏不可以调试;宏是直接替换的,当替换较多时浪费空间;宏虽然可以传类型但宏本身是无类型的;宏是带有副作用的;...而这些缺点正好可以由const来解决。从下面一段代码中就可以看出

#define MAX 5     //define定义的标识符
const int max=10  //此时未将Max放入内存中而是放到符号表中
int main()
{
	int i=MAX;  //预编译期间进行标识符的替换
	int j=max;  //此时为j分配内存,以后不再分配
	int m=MAX;  //再进行一次宏的替换,再分配内存
	int n=max;  //不再分内存配

因为编译器通常不为普通const只读变量分配存储空间,而是将他们保存在符号表中,这就使该变量成为一个编译期间的值,没有了存储与读内存的操作,从而使得效率较高。这就解决了为什仫在C++中以const来代替define定义的标识符和宏了吧

const修饰变量

const修饰变量时const可以在类型的左边也可以在类型的右边,比如

const int a=10;
int const a=10;

在C语言中const修饰变量使得该变量具有常性但依然是个变量(在C中const修饰的变量是常变量)

但是在C++中为了消除宏的缺点同时也需要定义常量,此时const修饰的变量去除了它在C中的变量的属性,完全升级为一个具有常性的量(在C++中const修饰的变量是常量)比如下列代码:

	const int a=10;
	int arr[a]={0};

数组的长度必须是一个代表常量的值,如果在.cpp下可以运行就可以说明在C++中const修饰的变量是否具有常性了;上述代码在.c文件中是不可运行的,在.cpp下可以运行的,这就说明在C++中const修饰的变量已经不具有变量的性质了,完全是一个常量

const修饰指针

const修饰一级指针

 1).const在*的左边

	int a=10;
	int b=20;
	const int *pa=&a;
	*pa=20;  //错误
	a=20;
	pa=&b;

const修饰的是*pa,说明指针pa所指向的内容不可以修改,但可以通过pa指针所指向的变量修改也可以改变指针变量本身;

2).const在*的右边

	int a=10;
	int b=20;
	int *const pa=&a;
	pa=&b;//(错误)
	*pa=b;

const修饰的是pa,说明指针变量本身是不可以被修改的,但可以修改指针所指向的内容;

 3).const即在*的左边也在*的右边

	int a=10;
	int b=20;
	const int *const pa=&a;
	pa=&b;//(错误)
	*pa=b;//(错误)

此时const即修饰*pa也修饰pa,说明指针所指向的内容是不可以修改的,指针变量本身也是不能被修改的

帮助记忆的小窍门:

如果我们把pa和a看作男女朋友关系,女生a可以换男朋友看作是可以修改变量本身的地址,女生a可以花男朋友的钱类似可以修改变量的内容;const在*的左边就类似这个女生a是可以换男朋友的但是不可以花男朋友的钱,const在*的右边就类似这个女生a是可以花男朋友钱的但是不可以换男朋友,const如果即在*的左边也在*的右边那这个女生可就惨了,即不可以换男朋友也不可以花男朋友的钱,是不是感觉很有意思呢?

const修饰二级指针

1).const在第一个*的左边

	int a=10;
	int b=20;
	int *pa=&a;
	int *pb=&b;
	const int **ppa=&pa;
	**ppa=b;//(错误)
	ppa=&pb;
	*ppa=&b;
	a=40;

指向关系如下图:

const修饰在第一个*的左边,去掉类型我们发现它修饰的是**pa,说明我们此时是不可以通过指向a这块空间的二级指针ppa来修改a的值的,但是可以通过a来改变这块空间的内容,也可以修改ppa指针变量本身

2).const放在两个*的中间

	int a=10;
	int b=20;
	int *pa=&a;
	int *pb=&b;
	int *const *ppa=&pa;
	ppa=&pb;
	*ppa=&b; //(错误)
	**ppa=b;

const修饰在两个*的中间,根据就近原则,我们知道const修饰的是*ppa,说明此时我们不可以改变ppa所指向的空间pa的内容的,但是我们可以修改ppa指针变量的本身,也可以修改二级指针ppa所指向空间a的值

3).const 放在第二个*的右边

	int a=10;
	int b=20;
	int *pa=&a;
	int *pb=&b;
	int **const ppa=&pa;
	ppa=&pb;   //(错误)
	*ppa=&b;
	**ppa=b;

const放在第二个*的右边,根据就近原则,我们知道const修饰的是ppa,说明此时我们是不可以修改二级指针ppa指针变量本身的地址,我们可以修改二级指针ppa所指向空间pa和pa所指向空间a的内容

const修饰二级指针还有很多情况,上述只讨论了只有一个const修饰的二级指针,只要把握要点,清楚const修饰的是什仫?二级指针本身?二级指针指向一级指针的内容?二级指针指向一级指针的地址?二级指针间接指向变量的内容?只要清楚了这些就可以很好的驾驭const修饰指针的问题了。

const修饰引用

1).const修饰引用即变量的别名,该别名是没有权限修改该变量的内容的,只能通过该变量修改内容

	int a=10;
	const int &refa=a;
	refa=20;  //(错误)
	a=20;

2).const修饰变量的权限是可以缩小的但不可以扩大

	const int a=10;
	int &refa=a;  //(错误)
	int b=20;
	const int &refb=b;

       3).const修饰全局变量,该全局变量存放在只读数据区,即使使用指针也无法修改该变量;定义时不一定分配空间在使用时才分配空间

const int n=10;   //const修饰全局变量
int main()
{

	int arr[n];   //只要说明n为常量也未分配空间
	const int *p=&n;  //此时才为n分配空间
	system("pause");
	return 0;
}

将const修饰的全局变量的地址给指针也就是使用时才分配地址

 4).常量具有常性,只有常引用可以引用常量

	int &refa=5;   //(错误)
	const int &refb=5;

5).引用的类型不匹配

	double d1=3.1;
	const int &refd1=d1;  //3
	d1=6.95;

注意:

1).在内存中为变量分配空间时是存在一个临时变量的,而这个临时变量是具有常性的(默认类型为const int)

2).当变量本身的名字和别名的类型不符合时,引用的就不是d1了而是这个临时的变量

3).既然是个临时的变量使用完后就会销毁,所以当再修改变量d1的值也不会影响refd1的值

6).const修饰函数的参数,修饰函数的返回值:

当希望在函数内部不可以随意修改该变量的值时可以给函数的参数加上const修饰

const也可以修饰函数的返回值,此时函数的返回值是不可被修改的或者当确实需要返回一个常性的值时可以用const修饰函数的返回值,比如类的六个默认的成员函数的拷贝构造函数就是传常引用,以日期类为例的拷贝构造函数

	Date(const Date& d)
		:_year(d._year)
		,_month(d._month)
		,_day(d._day)
	{}

 
const修饰成员函数 

           const修饰成员函数,在成员函数后面加const,const修饰this指针所指向的对象,也就是保证在调用这个成员函数的对象在函数内不会被改变

         

           以日期类为例观察const修饰成员函数时的具体传值过程

           

          日期类

          

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;

class Date
{
public:
	Date(int year,int month,int day)
		:_year(year)
		,_month(month)
		,_day(day)
	{}
	void Display()const
	{
		cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
	}
	void Display()
	{
		cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1(2016,8,10);
	d1.Display();

	const Date d2(d1);
	d2.Display();
	system("pause");
	return 0;
}

此时也就存在了下面几个问题,这也是我们之前提到的const修饰变量的权限问题(权限可以缩小但不可以扩大)

1).const对象不可以调用非const成员函数,可以调用const成员函数

2).非const对象可以调用非const的成员函数,也可以调用const成员函数

3).const成员函数可以调用其他的const成员函数,不可以调用非const的成员函数

4).非const成员函数内可以调用其他的成员函数,也可以调用非const成员函数

这是我个人的一点小理解,如果有读者知道有更多的用法请联系我,本人邮箱[email protected]

时间: 2024-10-03 15:01:04

详解关键字static,const,volatile的相关文章

c中常用的关键字static const volatile

在C语言中,关键字static有三个明显的作用:1). 在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变.2). 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问.它是一个本地的全局变量.3). 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用.那就是,这个函数被限制在声明它的模块的本地范围内使用.大多数应试者能正确回答第一部分,一部分能正确回答第二部分,同是很少的人能懂得第三部分.这是一个应试者的严重的缺点,因

详解java中的volatile关键字

一.为什么要有volatile关键字 估计很多java初学者都被volatile这个关键字迷惑过.虽然网上有很多讨论volatile的文章,但它们有的过于讲述底层原理,而没有说明其应用场景,让初学者看后还是一头雾水:有的过于使用类比讲解,造成了一定的错误,这样的文章更害人.下面,小弟试着分析下volatile关键字的作用及用法,希望能给大家带来一定的启发.文中错误之处,请各位大神指正. 我们知道,在多线程编程中,多个线程在访问共享变量时,必须进行必要的同步,否则很可能产生错误.synchroni

详解C中的volatile关键字【转】

本文转载自:http://www.cnblogs.com/yc_sunniwell/archive/2010/06/24/1764231.html volatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据.如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象.下面举例说明.在DSP开发中,经常需要等待某个事件的触发,所以经常会写

详解Java Static关键字

提起static关键字,相信大家绝对不会陌生,但是,想要完全说明白,猛的一想,发现自己好像又说不太明白... ...比方说,昨天被一个同学问起的时候... ... 当然,不是所有人都像我一样学艺不精的,但是像这样的基础不牢的人应该不少,因为常用,所以用大家都会,但是谈到精细之处都够呛.这篇博客是我翻出我原来的学习笔记再加上自己看的一些博客整理出来的,供基础知识不怎么牢靠的同学参考参考. 1. static 关键字要解决的问题 这里摘录一下<Java编程思想(第四版)>里关于static关键字的

C语言中auto,register,static,const,volatile的区别

1)auto 这个关键字用于声明变量的生存期为自动,即将不在任何类.结构.枚举.联合和函数中定义的变量视为全局变量,而在函数中定义的变量视为局部变量.这个关键字不怎么多写,因为所有的变量默认就是auto的. (2)register 这个关键字命令编译器尽可能的将变量存在CPU内部寄存器中而不是通过内存寻址访问以提高效率. (3)static 常见的两种用途: 1>统计函数被调用的次数; 2>减少局部数组建立和赋值的开销.变量的建立和赋值是需要一定的处理器开销的,特别是数组等含有较多元素的存储类

static \ const \ volatile 的含义

1.static 在函数体内,一个被声明为静态的变量在这一函数被调用的过程中维持其值不变 在模块内(函数体外),一个被声明为静态的变量可以被模块内的所有函数访问,但不能被模块外的其他函数访问,即它是一个本地的全局变量 在模块内,一个被声明为静态的啊函数只可以被这一模块内的其他函数调用,这个函数被限制在声明他的模块的本地范围内使用 2.const(搜索Dan Saks总结的const) const意味着"只读" //声明指针在C/C++中是从右往左读 const int a;//常整型数

java中静态代码块的用法 static用法详解和static静态导入

(一)java 静态代码块 静态方法区别一般情况下,如果有些代码必须在项目启动的时候就执行的时候,需要使用静态代码块,这种代码是主动执行的;需要在项目启动的时候就初始化,在不创建对象的情况下,其他程序来调用的时候,需要使用静态方法,这种代码是被动执行的. 静态方法在类加载的时候 就已经加载 可以用类名直接调用比如main方法就必须是静态的 这是程序入口两者的区别就是:静态代码块是自动执行的;静态方法是被调用的时候才执行的. 静态方法(1)在Java里,可以定义一个不需要创建对象的方法,这种方法就

详解PHP中const和define的区别

在PHP中定义常量时,可用const与define这两种方式,那他们到底有什么区别呢? const用于类成员变量定义,一旦定义且不能改变其值.define定义全局常量,在任何地方都可以访问. define不能定义在类中,而const必须定义在类中,并且const定义的变量必须通过类名::变量名来进行访问. const不能在条件语句中定义常量. const采用一个普通的常量名称(静态的标量),define可以采用任何表达式作为名称. const 总是大小写敏感,然而define()可以通过第三个参

PHP面向对象编程详解:类和对象

PHP面向对象编程详解:类和对象 从OOP的视角看,不应区分语言.无论是C++.无论是Java.无论是.net还有更多面向对象的语言,只要你了解了OO的真谛,便可以跨越语言,让你的思想轻松的跳跃.便没有对于Java..net.PHP 之间谁强谁弱的争执了. 希望这个介绍PHP5面向对象编程(OOP)的资料能让初学者受益,能让更多的PHPer开始转向OO的编程过程. 相对PHP4,PHP5在面向对象方面改变了很多.我们将只介绍PHP5环境下的面向对象.而我们必须改变自己来跟随PHP5的发展.如果代