局部变量
定义的时候系统不会初始化,其值为任意
全局变量
定义全部变量系统为其默认初始化
int | 0 |
char | '\0' |
float | 0 |
double | 0 |
pointer | NULL |
函数体内可以有重名变量
前提条件是需要用{}括起来
比如下面的代码就是对的,但是printf输出的是a=10
#include <iostream>
using namespace std;
int main()
{
int a = 0;
{int a = 10;
printf("a = %d",a);}
return 0;
}
下面就属于错误
#include <iostream>
using namespace std;
int main()
{
int a = 0;
int a = 10;
printf("a = %d",a);
return 0;
}
域名解析
全局变量和和局部变量同名时,可通过域名在函数中引用到全局变量,不加域名解析则引用局部变量
#include<iostream>
using namespace std;
int a = 10;
int main()
{
int a = 20;
cout << ::a << endl; // 10
cout << a << endl; // 20
return 0;
}
全局变量、局部变量、静态全局变量、静态局部变量的区别
作用域可分为 6 种:全局作用域,局部作用域,语句作用域,类作用域,命名空间作用域和文件作用域。
从作用域看:
全局变量具有全局作用域。全局变量只需在一个源文件中定义,就可以作用于所有的源文件。当然,其他不包含全局变量定义的源文件需要用extern 关键字再次声明这个全局变量。
静态局部变量具有局部作用域,它只被初始化一次,自从第一次被初始化直到程序运行结束都一直存在,它和全局变量的区别在于全局变量对所有的函数都是可见的,而静态局部变量只对定义自己的函数体始终可见。
局部变量也只有局部作用域,它是自动对象(auto),它在程序运行期间不是一直存在,而是只在函数执行期间存在,函数的一次调用执行结束后,变量被撤销,其所占用的内存也被收回。
静态全局变量也具有全局作用域,它与全局变量的区别在于如果程序包含多个文件的话,它作用于定义它的文件里,不能作用到其它文件里,即被static关键字修饰过的变量具有文件作用域。这样即使两个不同的源文件都定义了相同名字的静态全局变量,它们也是不同的变量。
从分配内存空间看:
全局变量,静态局部变量,静态全局变量都在静态存储区分配空间,而局部变量在栈里分配空间。
全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。这两者在存储方式上并无不同。
- 1)、静态变量会被放在程序的静态数据存储区(数据段)(全局可见)中,这样可以在下一次调用的时候还可以保持原来的赋值。这一点是它与堆栈变量和堆变量的区别。
- 2)、变量用static告知编译器,自己仅仅在变量的作用范围内可见。这一点是它与全局变量的区别。
从以上分析可以看出, 把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。因此static 这个说明符在不同的地方所起的作用是不同的。应予以注意。
Tips:
- A、若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间的耦合度;
- B、若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降低模块间的耦合度;
- C、设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时,需要考虑重入问题,因为他们都放在静态数据存储区,全局可见;
- D、如果我们需要一个可重入的函数,那么,我们一定要避免函数中使用static变量(这样的函数被称为:带“内部存储器”功能的的函数)
- E、函数中必须要使用static变量情况:比如当某函数的返回值为指针类型时,则必须是static的局部变量的地址作为返回值,若为auto类型,则返回为错指针。
static 全局变量:改变作用范围,不改变存储位置
static 局部变量:改变存储位置,不改变作用范围
静态函数 :在函数的返回类型前加上static关键字,函数即被定义为静态函数。静态函数与普通函数不同,它只能在声明它的文件当中可见,不能被其它文件使用。
如果在一个源文件中定义的函数,只能被本文件中的函数调用,而不能被同一程序其它文件中的函数调用,这种函数也称为内部函数。定义一个内部函数,只需在函数类型前再加一个“static”关键字即可。
常量的定义
(1) 使用#define预处理器
#define identifier value
(2) 使用const关键字
const 前缀声明指定类型的常量(只读,不能修改)
const type variable = value
宏定义 #define 和常量 const 的区别
类型和安全检查不同
宏定义是字符替换,没有数据类型的区别,同时这种替换没有类型安全检查,可能产生边际效应等错误;
const常量是常量的声明,有类型区别,需要在编译阶段进行类型检查
编译器处理不同
宏定义是一个"编译时"概念,在预处理阶段展开,不能对宏定义进行调试,生命周期结束与编译时期;
const常量是一个"运行时"概念,在程序运行使用,类似于一个只读行数据
存储方式不同
宏定义是直接替换,不会分配内存,存储于程序的代码段中;
const常量需要进行内存分配,存储与程序的数据段中
定义域不同
void f1 ()
{
#define N 12
const int n 12;
}
void f2 ()
{
cout<<N <<endl; //正确,N已经定义过,不受定义域限制
cout<<n <<endl; //错误,n定义域只在f1函数中
}
定义后能否取消和修改
宏定义可以通过#undef来使之前的宏定义失效
const常量定义后将在定义域内永久有效
void f1()
{
#define N 12
const int n = 12;
#undef N //取消宏定义后,即使在f1函数中,N也无效了
#define N 21//取消后可以重新定义
}
是否可以做函数参数
宏定义不能作为参数传递给函数
const常量可以在函数的参数列表中出现
const限定符定以后是不可以改变的,所以在定义时必须赋初始值,要不然是错误的,除非这个变量是用extern修饰的外部变量
const int A=10; //正确。
const int A; //错误,没有赋初始值。
extern const int A; //正确,使用extern的外部变量。
const char*, char const*的区别
Bjarne 在他的 The C++ Programming Language 里面给出过一个助记的方法: 把一个声明从右向左读。
char * const cp; ( * 读成 pointer to )
cp is a const pointer to char
const char * p;
p is a pointer to const char;
char const * p;
因为 C++ 里面没有 const* 的运算符,所以 const 只能属于前面的类型。
C++标准规定,const关键字放在类型或变量名之前等价的。
const int n=5; //same as below
int const m=10;
const int *p; //same as below const (int) * p
int const *q; // (int) const *p
char ** p1;
// pointer to pointer to char
const char **p2;
// pointer to pointer to const char
char * const * p3;
// pointer to const pointer to char
const char * const * p4;
// pointer to const pointer to const char
char ** const p5;
// const pointer to pointer to char
const char ** const p6;
// const pointer to pointer to const char
char * const * const p7;
// const pointer to const pointer to char
const char * const * const p8;
// const pointer to const pointer to const char