extern,static,const修饰变量的用法

本文详细介绍了C语言中extern, static, const修饰变量的作用和用法,包括它们在不同场景下的区别,以及如何影响变量的作用域、内存分配和程序优化。例如,extern用于声明全局变量,static限制变量的作用域,const用于创建只读变量,这些概念对于理解和编写高效、可靠的C程序至关重要。" 17894935,5284,EBS OAF多行表附件功能实现指南,"['EBS开发', 'OAF开发', '附件功能', '多行表']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 首先看两道道面试题:

变量的定义与声明有啥区别?

首先:变量的定义一定也是变量的初始化,反之则不成立, 在一定的作用域中,变量的声明可以有多个,但是定义只有一个;

  -》变量在定义时分配内存空间,同时也可能赋予初值;

  -》变量在声明时不会分配内存空间,说明该变量是存在的,指出了该变量的名字和位置。其作用是声明该变量是已在程序后面定义的变量

  如: 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只读变量与常量 【指针】

举例:有关字符串常量的疑惑

void main()
{
 
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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值