首先看两道道面试题:
变量的定义与声明有啥区别?
首先:变量的定义一定也是变量的初始化,反之则不成立, 在一定的作用域中,变量的声明可以有多个,但是定义只有一个;
-》变量在定义时分配内存空间,同时也可能赋予初值;
-》变量在声明时不会分配内存空间,说明该变量是存在的,指出了该变量的名字和位置。其作用是声明该变量是已在程序后面定义的变量
如: extern int i ; //声明外部变量;<=> extern i ;
如: int i ;//定义变量;
简要说明static的用法?
NO.1 修饰函数,使得函数成为静态函数,在此static并非指存储方式,只是说明该函数的作用域只是局限于本文件;
NO.2 修饰局部变量,成为静态局部变量,存储在静态区,即使函数运行结束,静态变量的值不会被销毁,下次调用该函数时,值仍存在;
NO.3 修饰全局变量,成为静态全局变量,存储在静态区,作用域仅限于变量被定义的文件中,其他文件即使使用extern也无法调用
用关键字const修饰的只读变量与常量的区别:
1. 常量是一个静态的值,不需要分配内存,enum类型和#define(注意define不是关键字)宏声明一个常量;变量需要分配内存;
2. const修饰的只读变量不能用来作为定义数组的维数,也不能放在case关键字后面。
(case 后面只能是整型或字符型的常量或常量表达式)
3. 常量是永远无法改变的,但是只读变量一般无法直接再次赋值,但是可以通过指针改变。
更多参考:
http://blog.sina.com.cn/liexusong1985
第2章const只读变量与常量 【指针】
举例:有关字符串常量的疑惑
{
char * p;
p = ( char * )malloc( sizeof ( char ));
p = " abc " ;
p[ 1 ] = p[ 0 ];
printf( " %s " ,p); printf( " %c\n " ,p[ 1 ]);
}
错误分析:
1. p 成为野指针,char* p =NULL; 给p分配的空间太小,sizeof(char)* 5;
2. "abc"是字符串常量,在静态区,静态区的常量空间不可修改,p[1]=p[0]出错
3. 正确代码:
void main()
{
char*p=NULL;
p=(char*)malloc(sizeof(char //判断内存分配是否成功;
{
strcpy(p,"abc");
p[1]=p[0];
}
printf("%s",p); printf("%c\n",p[1]);
free(p); //释放内存空间;
p=NULL;
}
用const的好处:
1.修饰函数的参数(说明了该参数应用目的)可以防止参数意外改动,增加程序的健壮性;
2.修饰只读变量同时进行初始化,以后此常量不再改变,可以节省空间,避免不必要的内存空间分配,提高效率;
3.对指针来说,可以指定指针本身为const,也可以指定指针所指的数据为const,或二者同时指定为const;
4.修饰函数的返回值,返回值为const型,不能作为左值;
5.修饰函数体时,表示是一个常函数,不能改变其中变量的值;
#define M 3 //宏常量
const int N=5; //此时并未将N 放入内存中
......
int i=N; //此时为N 分配内存,以后不再分配!
int I=M; //预编译期间进行宏替换,分配内存
int j=N; //没有内存分配
int J=M; //再进行宏替换,又一次分配内存!
3.通过给优化器一些附加的信息,const也许能产生更紧凑的代码。
分辨下列声明:
Const int a;
int const a;
const int *a;
int * const a;
int const * a const;
前两个的作用是一样,a是一个常整型数。第三个意味着a是一个指向常整型数的指针(也就是,整型数是不可修改的,但指针可以)。第四个意思a是一个指向整型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)。最后一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改的)。用extern,static,const定义全局变量的差异和用法:
(1)若要求某个文件中的全局变量是任何其他文件共享的,只要在头文件中extern声明一下,在某一文件定义下,任何文件均可共享这个全局变量;
在“myhead.h”中声明外部全局变量:extern int a;
/*注意1:变量在声明时内存并不分配相应的空间,只有在定义时内存才分配相应的空间*/
在“1.c”中:
#include"myhead.h"
int a=5; //外部全局变量;
int main()
{
int b=0; //普通变量;
static int c;……//静态局部变量;
a+=3;
other();
b+=3;
other();
}
在“2.c”中:
#include"myhead.h"
void other()
{
int b=3;
static int c=3;
a+=5;
b+=5;
c+=5;
printf("%d,%d,%d",a,b,c);
c=b;
}
得出结果:
13,8,8 18,8,13
/*注意2:在头文件中,只能对外部全局变量进行声明,而不能定义,否则,在编译过程中会提示出现重复定义的错误,因为两个.c文件都包含了头文件*/
/*自我总结3:此时extern修饰的变量作用域为多个文件,效果如同static修饰的局部变量*/
或者:仅仅在某一文件中定义全局变量int a;
在其他文件使用时,用extern对变量a声明下,得出的结果是相同的。
等价于函数:”main.c”
#include<stdio.h>
#include<stdlib.h>
int main()
{
extern int a;
/*在同一文件中,若前面的函数要引用在其后面定义的外部变量(全局变量)时,要用extern加以说明*/
int b=0;
static int c;
a+=3;
other();
b+=3;
other();
}
int a=5;
other()
{
int b=3;
static int c=3;
a+=5;
b+=5;
c+=5;
printf("%d,%d,%d",a,b,c);
c=b;
}
(2)若在定义全局变量前加static,说明该变量只有该文件内部可以使用,其他文件无法使用。
有两条重要的结论:
1. static 和extern不能同时定义一个相同的变量;
2. 用static定义的全局变量(函数)时,只作用在本文件中,其他文件不能应用。
所以,一般static定义全局变量在源文件中,而不放置在头文件中。
/*若在头文件中定义了static int a=5;则在多个.c文件编译可以通过,声明同时定义,多个文件编译时内存给a分配了不同的空间,其中每个.c文件中a=5,不会因为文件中a的改变而改变,不放置在头文件中,可防止信息污染;*/
用extern,static,const定义局部变量的差异和用法:
用static定义局部变量时:改变了局部变量的生命周期(作用域还仅限于函数)。
普通的局部变量存放在内存的动态区(栈区),静态的局部变量存在内存的静态区,
地址不再随着函数调用的结束而消失,而是等整个程序结束后才消失。(如上例);
不用extern来定义一个局部变量,没有意义。
关于const:
除了定义只读变量,可以用于修饰函数的参数,返回值,函数的定义体,以此来提高函数的健壮性。
用于修饰函数的参数:
如:经过const修饰的参数将失去输出的功能;
通常const只修饰作为输入的参数:
参数为指针传递时:如:strcpy(char *strdes,const char*strsource);
/*防止意外改动输入参数strsource的内容*/
参数为至传递时:通常不用const修饰,会自动产生一个临时变量来复制输入参数,而不会改变原值。
参数为引用传递时,情况通指针传递 void func(const int& a);
用于修饰函数的返回值:
若const 用于修饰指针传递方式的函数返回值,则返回指针值就不能被修改,同样要用const修饰的同类指针接受返回值;
如: const int* String(int * r);
const int* p=String(ptr);
若是值传递,返回值在临时的存储区,一般不用const修饰;
若是引用传递,情况与指针类似,但是容易出错(慎用);
fmoonstar 更新至2011.11.30