C语言中的一些基本概念

1。变量的声名与定义

     声明一个变量意味着向编译器描述变量的类型,但并不为变量分配存储空间。定义一个变量意味着在声明变量的同时还要为变量分配存储空间。在定义一个变量的同时还可以对变量进行初始化。

   a. 对于局部变量来说,声名即为定义,也可以说局部变量通常只定义不声明或者,局部变量声名定义没有区别。声名与定义的区别是针对全局变量来说的。

   b.而全局变量多在源文件中定义,在头文件中声明。  由于C语言代码是以文件为单位来组织的,在一个源程序所有源文件中,一个外部变量或函数只能在某个文件中定义一次,而其它文件可以通过extern声明来访问它(定义外部变量或函数的源文件中也可以包含对该外部变量的extern声明)。

    注:C语言程序可以看成由一系列外部对象构成,这些外部对象可能是变量或函数。而内部变量是指定义在函数内部的函数参数及变量。外部变量定义在函数之外,因此可以在许多函数中使用。由于C语言不允许在一个函数中定义其它函数,因此函数本身只能是“外部的”。

 

2。c语言中的静态(static)与动态(auto)
     

     函数中的局部变量,其缺省格式是自动变量类型。例如,在函数体中int b, c=3; 和auto int b, c=3; 是等价的。
自动变量是动态分配存储空间的,函数结束后就释放。自动变量如不赋初值,则它的值是一个不确定的值。函数中的形参和在函数中定义的变量,包括在符合语句中定义的变量都属此类。

     而static则可以限定变量或函数为静态存储。如果用static限定外部变量与函数,则可以将该对象的作用域限定为被编译源文件的剩余部分。通过static限定外部对象,可以达到隐藏外部对象的目的。因而,static限定的变量或函数不会和同一程序中其它文件中同名的相冲突。如果用static限定内部变量,则该变量从程序一开始就拥有内存,不会随其所在函数的调用和退出而分配和消失。

3。静态变量

    a.静态局部变量:静态局部变量是指在函数体内声明和定义的局部变量,它仅供本函数使用,即其他函数不能调用它。静态局部变量的值在函数调用结束后不消失而保留原值,即其占用的存储单元不释放,在下一次函数调用时,该变量已有值,就是上一次函数调用结束时的值。

    静态局部变量在静态存储区分配存储单元,在程序的整个运行期间都不释放。静态局部变量是在编译时赋初值的,即只赋初值一次。
    在SDT编译器中,建议对静态局部变量赋初值,否则该静态局部变量的初值为不确定值。在其他编译器中,未初始化的静态局部变量的初值可能为零,这由具体的编译器所决定,使用前最好测试一下。


    b.静态全局变量

    全局变量本身就是静态存储方式,静态全局变量当然也是静态存储方式。但是他们的作用域,非静态全局 变量的作用域是整个源程序(多个源文件可以共同使用); 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。
因为静态外部变量只能在本文件中使用,所以静态外部变量应该在当前源文件中声明和定义。

    注:若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间的耦合度。

         若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降低模块间的耦合度
  

4。静态函数

    由于C语言不允许在一个函数中定义其它函数,因此函数本身只能是“外部的”。

    静态函数,也叫内部函数。只能被本文件中的函数调用,而不能被同一程序其它文件中的函数调用。区别于一般的非静态函数(外部函数)。

    使用静态函数的好处:

    a. 静态函数会被自动分配在一个一直使用的存储区,直到退出应用程序实例,避免了调用函数时压栈出栈,速度快很多。 

    b.关键字“static”,译成中文就是“静态的”。但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件。 使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同名,因为同名也没有关系。


5。全局数据区,栈和堆

     变量在c里面可分为存在全局数据区、栈和堆里。其实我们平时所说的堆栈是栈而不包含堆。

      int a ;
        main()
        {
             int b ;
             int c* = (int *)malloc(sizeof(int));
        }

       a是全局变量,b是栈变量,c是堆变量。

       static对全局变量的修饰,可以认为是限制了只能是本文件引用此变量。有的程序是由好多.c文件构成。彼此可以互相引用变量,但加入static修饰之后,只能被本文件中函数引用此变量。
        static对栈变量的修饰,可以认为栈变量的生命周期延长到程序执行结束时。一般来说,栈变量的生命周期由OS管理,在退栈的过程中,栈变量的生命也就结束了。但加入static修饰之后,变量已经不在存储在栈中,而是和全局变量一起存储。同时,离开定义它的函数后不能使用,但如再次调用定义它的函数时,它又可继续使用, 而且保存了前次被调用后留下的值。
       static对函数的修饰与对全局变量的修饰相似,只能被本文件中的函数调用,而不能被同一程序其它文件中的函数调用。

       static 声明的变量在C语言中有两方面的特征:
  1)、变量会被放在程序的全局存储区中,这样可以在下一次调用的时候还可以保持原来的赋值。这一点是它与堆栈变量和堆变量的区别。
  2)、变量用static告知编译器,自己仅仅在变量的作用范围内可见。这一点是它与全局变量的区别。 

 

  6. 函数可重入

      所谓的函数是可重入的(也可以说是可预测的),即:只要输入数据相同就应产生相同的输出。
 

     unsigned int sum_int( unsigned int base )
     {
      unsigned int index;
      static unsigned int sum = 0; // 注意,是static类型的。
      for (index = 1; index <= base; index++)
      {
       sum += index;
      }
      return sum;
     }

  这个函数之所以是不可预测的,就是因为函数中使用了static变量,因为static变量的特征,这样的函数被称为:带“内部存储器”功能的的函数。因此如果我们需要一个可重入的函数,那么,我们一定要避免函数中使用static变量,这种函数中的static变量,使用原则是,能不用尽量不用。
  将上面的函数修改为可重入的函数很简单,只要将声明sum变量中的static关键字去掉,变量sum即变为一个auto 类型的变量,函数即变为一个可重入的函数。
  当然,有些时候,在函数中是必须要使用static变量的,比如当某函数的返回值为指针类型时,则必须是static的局部变量的地址作为返回值,若为auto类型,则返回为错指针。

   7。字符串常量

     在c语言程序中可以用两种方法访问一个字符串

     a. 用字符数组存放一个字符串,然后输出该字符串

     main()
     {

           char string[]="I love you!";

           printf("%s\n, string");

     }

   在上面这个程序段中,是用字符串常量来使字符数组初始化。

    b. 用字符指针指向一个字符串。

    可以不定义字符数组,而定义一个字符指针。用字符指针指向字符串中的字符。

    main()
     {

           char *string="I love you!";

           printf("%s\n, string");

     }

    这里没有定义字符数组,在程序中定义了一个字符指针变量string。给定一个字符串常量"I love you!"。C语言对字符串常量是按字符数组来处理的,在内存开辟了一个字符数组来存放字符串常量。程序在定义字符指针变量string时 把字符串首地址(即存放字符串的字符数组的首地址)附给string。

  举个例子:

   char * GetMemory(void)

   {

      char p[]="I love you";

      return p;

   }

   void Test (void)

  {

      char *str=NULL:

      str= GetMemory();

      printf(str);

  }
    由于 GetMemory返回i的指针是指向 “栈内存” 的指针,该指针的地址不是 NULL,但其原来的内容在函数调用完成后已经清除,新内容不可知。

    char * GetMemory(void)

   {

      char *p="I love you";

      return p;

   }

   void Test (void)

  {

      char *str=NULL:

      str= GetMemory();

      printf(str);

  }
   而 以上这段代码,这可以正确输出 字符串“I love you”。这是因为,“I love you” 作为 字符串常量 是在整个程序执行的工程中都存在的。但是不能由于其是常量,试图通过指针对其中的内容进行修改的话,运行时会提示段错误。

 注意: 字符数组可以在变量定义时整体赋初值,但不能在赋值语句中整体赋值。

posted @ 2009-03-10 21:24  红袖添香  阅读(1620)  评论(0编辑  收藏  举报