App下載

帶你了解C語(yǔ)言自動(dòng)變量的幾種類型

猿友 2020-07-30 10:47:39 瀏覽數(shù) (8243)
反饋

首先先了解一下什么是自動(dòng)變量,屬于自動(dòng)存儲(chǔ)類別的變量具有自動(dòng)存儲(chǔ)期、塊作用域且無(wú)鏈接。默認(rèn)情況下,聲明在塊或函數(shù)頭中的任何變量都屬于自動(dòng)存儲(chǔ)類別。一般情況下,不作專門(mén)說(shuō)明的局部變量,均是自動(dòng)變量。

關(guān)鍵字auto

為了更清楚地表達(dá)你的意圖(例如,為了表明有意覆蓋一個(gè)外部變量定義,或者強(qiáng)調(diào)不要把該變量改為其他存儲(chǔ)類別),可以顯式使用關(guān)鍵字auto,如下所示:

int main(void)
{
  auto int plox;

關(guān)鍵字auto是存儲(chǔ)類別說(shuō)明符(storage-class specifier)。auto關(guān)鍵字在C++中的用法完全不同,如果編寫(xiě)C/C++兼容的程序,最好不要使用auto作為存儲(chǔ)類別說(shuō)明符。

塊作用域無(wú)鏈接意味著只有在變量定義所在的塊中才能通過(guò)變量名訪問(wèn)該變量(當(dāng)然,參數(shù)用于傳遞變量的值和地址給另一個(gè)函數(shù),但是這是間接的方法)。另一個(gè)函數(shù)可以使用同名變量,但是該變量是存儲(chǔ)在不同內(nèi)存位置上的另一個(gè)變量。

變量具有自動(dòng)存儲(chǔ)期意味著,程序在進(jìn)入該變量聲明所在的塊時(shí)變量存在,程序在退出該塊時(shí)變量消失。原來(lái)該變量占用的內(nèi)存位置現(xiàn)在可做他用。

嵌套快的情況

接下來(lái)分析一下嵌套塊的情況。塊中聲明的變量?jī)H限于該塊及其包含的塊使用。

int loop(int n)
{
     int m;          // m in scope
     scanf("%d", &m);
     {
          int i;    // both m and i in scope
          for (i = m; i < n; i++)
               puts("i is local to a sub-blockn");
     }
     return m;     // m in scope, i gone
}

在上面的代碼中,i僅在內(nèi)層塊中可見(jiàn)。如果在內(nèi)層塊的前面或后面使用i,編譯器會(huì)報(bào)錯(cuò)。通常,在設(shè)計(jì)程序時(shí)用不到這個(gè)特性。然而,如果這個(gè)變量?jī)H供該塊使用,那么在塊中就近定義該變量也很方便。這樣,可以在靠近使用變量的地方記錄其含義。另外,這樣的變量只有在使用時(shí)才占用內(nèi)存。變量nm分別定義在函數(shù)頭和外層塊中,它們的作用域是整個(gè)函數(shù),而且在調(diào)用函數(shù)到函數(shù)結(jié)束期間都一直存在。

如果內(nèi)層塊中聲明的變量與外層塊中的變量同名會(huì)怎樣??jī)?nèi)層塊會(huì)隱藏外層塊的定義。但是離開(kāi)內(nèi)層塊后,外層塊變量的作用域又回到了原來(lái)的作用域。程序hiding.c演示了這一過(guò)程。

// hiding.c -- variables in blocks
#include <stdio.h>
int main()
{
    int x = 30;      // original x


    printf("x in outer block: %d at %pn", x, &x);
    {
        int x = 77;  // new x, hides first x
        printf("x in inner block: %d at %pn", x, &x);
    }
    printf("x in outer block: %d at %pn", x, &x);
    while (x++ < 33) // original x
    {
        int x = 100; // new x, hides first x
        x++;
        printf("x in while loop: %d at %pn", x, &x);
    }
    printf("x in outer block: %d at %pn", x, &x);


    return 0;
}

下面是該程序的輸出:

x in outer block: 30 at 0x7fff5fbff8c8
x in inner block: 77 at 0x7fff5fbff8c4
x in outer block: 30 at 0x7fff5fbff8c8
x in while loop: 101 at 0x7fff5fbff8c0
x in while loop: 101 at 0x7fff5fbff8c0
x in while loop: 101 at 0x7fff5fbff8c0
x in outer block: 34 at 0x7fff5fbff8c8

首先,程序創(chuàng)建了變量x并初始化為30,如第1條printf()語(yǔ)句所示。然后,定義了一個(gè)新的變量x,并設(shè)置為77,如第2條printf()語(yǔ)句所示。根據(jù)顯示的地址可知,新變量隱藏了原始的x。第3條printf()語(yǔ)句位于第1個(gè)內(nèi)層塊后面,顯示的是原始的x的值,這說(shuō)明原始的x既沒(méi)有消失也不曾改變。也許該程序最難懂的是while循環(huán)。

while循環(huán)的測(cè)試條件中使用的是原始的x

while(x++ < 33)

在該循環(huán)中,程序創(chuàng)建了第3個(gè)x變量,該變量只定義在while循環(huán)中。所以,當(dāng)執(zhí)行到循環(huán)體中的x++時(shí),遞增為101的是新的x,然后printf()語(yǔ)句顯示了該值。每輪迭代結(jié)束,新的x變量就消失。然后循環(huán)的測(cè)試條件使用并遞增原始的x,再次進(jìn)入循環(huán)體,再次創(chuàng)建新的x。在該例中,這個(gè)x被創(chuàng)建和銷毀了3次。注意,該循環(huán)必須在測(cè)試條件中遞增x,因?yàn)槿绻谘h(huán)體中遞增x,那么遞增的是循環(huán)體中創(chuàng)建的x,而非測(cè)試條件中使用的原始x。

我們使用的編譯器在創(chuàng)建while循環(huán)體中的x時(shí),并未復(fù)用內(nèi)層塊中x占用的內(nèi)存,但是有些編譯器會(huì)這樣做。

該程序示例的用意不是鼓勵(lì)讀者要編寫(xiě)類似的代碼(根據(jù)C的命名規(guī)則,要想出別的變量名并不難),而是為了解釋在內(nèi)層塊中定義變量的具體情況。

沒(méi)有花括號(hào)的塊

前面提到一個(gè)C99特性:作為循環(huán)或if語(yǔ)句的一部分,即使不使用花括號(hào)({}),也是一個(gè)塊。更完整地說(shuō),整個(gè)循環(huán)是它所在塊的子塊(sub-block),循環(huán)體是整個(gè)循環(huán)塊的子塊。與此類似,if語(yǔ)句是一個(gè)塊,與其相關(guān)聯(lián)的子語(yǔ)句是if語(yǔ)句的子塊。這些規(guī)則會(huì)影響到聲明的變量和這些變量的作用域。程序forc99.c演示了for循環(huán)中該特性的用法。

// forc99.c -- new C99 block rules
#include <stdio.h>
int main()
{
    int n = 8;


    printf("   Initially, n = %d at %pn", n, &n);
    for (int n = 1; n < 3; n++)
        printf("      loop 1: n = %d at %pn", n, &n);
    printf("After loop 1, n = %d at %pn", n, &n);
    for (int n = 1; n < 3; n++)
    {
        printf(" loop 2 index n = %d at %pn", n, &n);
        int n = 6;
        printf("      loop 2: n = %d at %pn", n, &n);
        n++;
    }
    printf("After loop 2, n = %d at %pn", n, &n);


    return 0;
}

假設(shè)編譯器支持C語(yǔ)言的這個(gè)新特性,該程序的輸出如下:

Initially, n = 8 at 0x7fff5fbff8c8
loop 1: n = 1 at 0x7fff5fbff8c4
loop 1: n = 2 at 0x7fff5fbff8c4
After loop 1, n = 8 at 0x7fff5fbff8c8
loop 2 index n = 1 at 0x7fff5fbff8c0
loop 2: n = 6 at 0x7fff5fbff8bc
loop 2 index n = 2 at 0x7fff5fbff8c0
loop 2: n = 6 at 0x7fff5fbff8bc
After loop 2, n = 8 at 0x7fff5fbff8c8

需要注意的一點(diǎn):

支持C99C11有些編譯器并不支持C99/C11的這些作用域規(guī)則(Microsoft Visual Studio 2012就是其中之一)。有些編譯會(huì)提供激活這些規(guī)則的選項(xiàng)。例如,撰寫(xiě)本書(shū)時(shí),gcc默認(rèn)支持了C99的許多特性,但是要用–std=c99選項(xiàng)激活程序清單12.2中使用的特性:

gcc --std=c99 forc99.c

與此類似,gccclang都要使用–std=c1x-std=c11選項(xiàng),才支持C11特性。

程序forc99.c第1個(gè)for循環(huán)頭中聲明的n,其作用域作用至循環(huán)末尾,而且隱藏了原始的n。但是,離開(kāi)循環(huán)后,原始的n又起作用了。

第2個(gè)for循環(huán)頭中聲明的n作為循環(huán)的索引,隱藏了原始的n。然后,在循環(huán)體中又聲明了一個(gè)n,隱藏了索引n。結(jié)束一輪迭代后,聲明在循環(huán)體中的n消失,循環(huán)頭使用索引n進(jìn)行測(cè)試。當(dāng)整個(gè)循環(huán)結(jié)束時(shí),原始的n又起作用了。再次提醒讀者注意,沒(méi)必要在程序中使用相同的變量名。如果用了,各變量的情況如上所述。

自動(dòng)變量的初始化

自動(dòng)變量不會(huì)初始化,除非顯式初始化它??紤]下面的聲明:

int main(void)
{
  int repid;
  int tents = 5;

tents變量被初始化為5,但是repid變量的值是之前占用分配給repid的空間中的任意值(如果有的話),別指望這個(gè)值是0??梢杂梅浅A勘磉_(dá)式(non-constantexpression)初始化自動(dòng)變量,前提是所用的變量已在前面定義過(guò):

int main(void)
{
  int repid;
  int tents = 5;

以上就是關(guān)于C語(yǔ)言的幾種自動(dòng)變量的說(shuō)明了,有興趣的同學(xué)可以看一下C語(yǔ)言的相關(guān)教程

C教程:http://m.hgci.cn/c/

C

0 人點(diǎn)贊