日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

【C++】C/C++ 中 static 的用法全局变量与局部变量

發布時間:2023/11/27 生活经验 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【C++】C/C++ 中 static 的用法全局变量与局部变量 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

C/C++ 中 static 的用法全局變量與局部變量

目錄

1. 什么是static?

1.1 static 的引入

1.2 靜態數據的存儲

2. 在 C/C++ 中static的作用

2.1 總的來說

2.2 靜態變量與普通變量

2.3 靜態局部變量有以下特點:

實例

3. static 用法

3.1 在 C++ 中

3.2 靜態類相關

3.3 總結:

實例


1. 什么是static?

static 是 C/C++ 中很常用的修飾符,它被用來控制變量的存儲方式和可見性。

1.1 static 的引入

函數內部定義的變量,當程序執行到它的定義處時,編譯器為它在棧上分配空間,函數在棧上分配的空間在此函數執行結束時會釋放掉,這樣就產生了一個問題: 如果想將函數中此變量的值保存至下一次調用時,如何實現? 最容易想到的方法是定義為全局的變量,但定義一個全局變量有許多缺點,最明顯的缺點是破壞了此變量的訪問范圍(使得在此函數中定義的變量,不僅僅只受此函數控制)。static 關鍵字則可以很好的解決這個問題

另外,在 C++ 中,需要一個數據對象為整個類而非某個對象服務,同時又力求不破壞類的封裝性,即要求此成員隱藏在類的內部,對外不可見時,可將其定義為靜態數據。

1.2 靜態數據的存儲

全局(靜態)存儲區:分為 DATA 段和 BSS 段。DATA 段(全局初始化區)存放初始化的全局變量和靜態變量;BSS 段(全局未初始化區)存放未初始化的全局變量和靜態變量。程序運行結束時自動釋放。其中BBS段在程序執行之前會被系統自動清0,所以未初始化的全局變量和靜態變量在程序執行之前已經為0。存儲在靜態數據區的變量會在程序剛開始運行時就完成初始化,也是唯一的一次初始化。

在 C++ 中 static 的內部實現機制:靜態數據成員要在程序一開始運行時就必須存在。因為函數在程序運行中被調用,所以靜態數據成員不能在任何函數內分配空間和初始化

這樣,它的空間分配有三個可能的地方,一是作為類的外部接口的頭文件,那里有類聲明;二是類定義的內部實現,那里有類的成員函數定義三是應用程序的 main() 函數前的全局數據聲明和定義處。

靜態數據成員要實際地分配空間,故不能在類的聲明中定義(只能聲明數據成員)。類聲明只聲明一個類的"尺寸和規格",并不進行實際的內存分配,所以在類聲明中寫成定義是錯誤的它也不能在頭文件中類聲明的外部定義,因為那會造成在多個使用該類的源文件中,對其重復定義。

static 被引入以告知編譯器,將變量存儲在程序的靜態存儲區而非棧上空間,靜態數據成員按定義出現的先后順序依次初始化,注意靜態成員嵌套時,要保證所嵌套的成員已經初始化了。消除時的順序是初始化的反順序。

優勢:可以節省內存,因為它是所有對象所公有的,因此,對多個對象來說,靜態數據成員只存儲一處,供所有對象共用。靜態數據成員的值對每個對象都是一樣,但它的值是可以更新的。只要對靜態數據成員的值更新一次,保證所有對象存取更新后的相同的值,這樣可以提高時間效率。


2. 在 C/C++ 中static的作用

2.1 總的來說

  • (1)在修飾變量的時候,static 修飾的靜態局部變量只執行初始化一次,而且延長了局部變量的生命周期,直到程序運行結束以后才釋放。

  • (2)static 修飾全局變量的時候,這個全局變量只能在本文件中訪問,不能在其它文件中訪問,即便是 extern 外部聲明也不可以。

  • (3)static 修飾一個函數,則這個函數的只能在本文件中調用,不能被其他文件調用。static 修飾的變量存放在全局數據區的靜態變量區,包括全局靜態變量和局部靜態變量,都在全局數據區分配內存。初始化的時候自動初始化為 0。

  • (4)不想被釋放的時候,可以使用static修飾。比如修飾函數中存放在棧空間的數組。如果不想讓這個數組在函數調用結束釋放可以使用 static 修飾。

  • (5)考慮到數據安全性(當程序想要使用全局變量的時候應該先考慮使用 static)。

2.2 靜態變量與普通變量

靜態全局變量有以下特點:

  • (1)靜態變量都在全局數據區分配內存,包括后面將要提到的靜態局部變量;

  • (2)未經初始化的靜態全局變量會被程序自動初始化為0(在函數體內聲明的自動變量的值是隨機的,除非它被顯式初始化,而在函數體外被聲明的自動變量也會被初始化為 0);

  • (3)靜態全局變量在聲明它的整個文件都是可見的,而在文件之外是不可見的。

優點:靜態全局變量不能被其它文件所用;其它文件中可以定義相同名字的變量,不會發生沖突。

(1)全局變量和全局靜態變量的區別

  • 1)全局變量是不顯式用 static 修飾的全局變量,全局變量默認是有外部鏈接性的,作用域是整個工程,在一個文件內定義的全局變量,在另一個文件中,通過 extern 全局變量名的聲明,就可以使用全局變量。

  • 2)全局靜態變量是顯式用 static 修飾的全局變量,作用域是聲明此變量所在的文件,其他的文件即使用 extern 聲明也不能使用。

2.3 靜態局部變量有以下特點:

  • (1)該變量在全局數據區分配內存;

  • (2)靜態局部變量在程序執行到該對象的聲明處時被首次初始化,即以后的函數調用不再進行初始化

  • (3)靜態局部變量一般在聲明處初始化,如果沒有顯式初始化,會被程序自動初始化為 0;

  • (4)它始終駐留在全局數據區,直到程序運行結束。但其作用域為局部作用域,當定義它的函數或語句塊結束時,其作用域隨之結束。

一般程序把新產生的動態數據存放在堆區,函數內部的自動變量存放在棧區。自動變量一般會隨著函數的退出而釋放空間,靜態數據(即使是函數內部的靜態局部變量)也存放在全局數據區。全局數據區的數據并不會因為函數的退出而釋放空間。

看下面的例子:

實例

//example:
#include <stdio.h> ?
#include <stdlib.h> ?
int k1 = 1;
int k2;
static int k3 = 2;
static int k4;
int main()
{static int m1 = 2, m2;int i = 1;char*p;char str[10] = "hello";char*q = "hello";p = (char *)malloc(100);free(p);printf("棧區-變量地址 ?  i:%p\n", &i);printf("棧區-變量地址 ? p:%p\n", &p);printf("棧區-變量地址 str:%p\n", str);printf("棧區-變量地址 ? q:%p\n", &q);printf("堆區地址-動態申請:%p\n", p);printf("全局外部有初值 k1:%p\n", &k1);printf(" ? 外部無初值 k2:%p\n", &k2);printf("靜態外部有初值 k3:%p\n", &k3);printf(" ? 外靜無初值 k4:%p\n", &k4);printf("  內靜態有初值 m1:%p\n", &m1);printf("  內靜態無初值 m2:%p\n", &m2);printf(" ?  文字常量地址:%p, %s\n", q, q);printf(" ? ?  程序區地址:%p\n", &main);return 0;
}

輸出結果如下:


3. static 用法

3.1 在 C++ 中

static 關鍵字最基本的用法是:

  • 1、被 static 修飾的變量屬于類變量,可以通過類名.變量名直接引用,而不需要 new 出一個類來

  • 2、被 static 修飾的方法屬于類方法,可以通過類名.方法名直接引用,而不需要 new 出一個類來

被 static 修飾的變量、被 static 修飾的方法統一屬于類的靜態資源,是類實例之間共享的,換言之,一處變、處處變。

在 C++ 中,靜態成員是屬于整個類的而不是某個對象,靜態成員變量只存儲一份供所有對象共用。所以在所有對象中都可以共享它。使用靜態成員變量實現多個對象之間的數據共享不會破壞隱藏的原則,保證了安全性還可以節省內存。

靜態成員的定義或聲明要加個關鍵 static。靜態成員可以通過雙冒號來使用即 <類名>::<靜態成員名>

3.2 靜態類相關

通過類名調用靜態成員函數和非靜態成員函數:

class Point ?
{ ?
public: ? void init() ?{ ? ?} ?static void output() ?{ ?} ?
}; ?
void main() ?
{ ?Point::init(); ?Point::output(); ?
}

報錯:

'Point::init' : illegal call of non-static member function

結論 1:

不能通過類名來調用類的非靜態成員函數必須通過對象實例化來調用。

通過類的對象調用靜態成員函數和非靜態成員函數。

class Point ?
{ ?
public: ? void init() ?{ ? ?} ?static void output() ?{ ?} ?
}; 
void main() ?
{ ?Point pt; ?pt.init(); ?pt.output(); ?
}

編譯通過。

結論 2

類的對象可以使用靜態成員函數和非靜態成員函數。

在類的靜態成員函數中使用類的非靜態成員。

#include <stdio.h> ?
class Point ?
{ ?
public: ? void init() ?{ ? ?} ?static void output() ?{ ?printf("%d\n", m_x); ?} ?
private: ?int m_x; ?
}; ?
void main() ?
{ ?Point pt; ?pt.output(); ?
}

編譯出錯:

error C2597: illegal reference to data member 'Point::m_x' in a static member function

因為靜態成員函數屬于整個類,在類實例化對象之前就已經分配空間了,而類的非靜態成員必須在類實例化對象后才有內存空間,所以這個調用就出錯了,就好比沒有聲明一個變量卻提前使用它一樣。

結論3:靜態成員函數中不能引用非靜態成員。

在類的非靜態成員函數中使用類的靜態成員。

class Point ?
{ ?
public: ? void init() ?{ ? ?output(); ?} ?static void output() ?{ ?} ?
}; ?
void main() ?
{ ?Point pt; ?Pt.init();pt.output(); ?
}

編譯通過。

結論 4:類的非靜態成員函數可以調用靜態成員函數,但反之不能。

使用類的靜態成員變量。

#include <stdio.h> ?
class Point ?
{ ?
public: ? Point() ?{ ? ?m_nPointCount++; ?} ?~Point() ?{ ?m_nPointCount--; ?} ?static void output() ?{ ?printf("%d\n", m_nPointCount); ?} ?
private: ?static int m_nPointCount; ?
}; ?
void main() ?
{ ?Point pt; ?pt.output(); ?
}

Ctrl+F7 編譯無錯誤,按 F7 生成 EXE 程序時報鏈接錯誤。

error LNK2001: unresolved external symbol "private: static int Point::m_nPointCount" (?m_nPointCount@Point@@0HA)

這是因為類的靜態成員變量在使用前必須先初始化。

main() 函數前加上 int Point::m_nPointCount = 0; 再編譯鏈接無錯誤,運行程序將輸出 1。

結論 5類的靜態成員變量必須先初始化再使用。

思考總結:靜態資源屬于類,但是是獨立于類存在的。從 生命歷程來看類的加載機制的角度講,靜態資源是類初始化的時候加載的,而非靜態資源是類實例化對象的時候加載的。 類的初始化早于類實例化對象,比如 Class.forName("xxx") 方法,就是初始化了一個類,但是并沒有實例化對象,只是加載這個類的靜態資源罷 了。所以對于靜態資源來說,它是不可能知道一個類中有哪些非靜態資源的;但是對于非靜態資源來說就不一樣了,由于它是實例化對象出來之后產生的,因此屬于類的這些東西它都能認識。所以上面的幾個問題答案就很明確了:

  • 1)靜態方法能不能引用非靜態資源?不能,實例化對象的時候才會產生的東西,對于初始化后就存在的靜態資源來說,根本不認識它。

  • 2)靜態方法里面能不能引用靜態資源?可以,因為都是類初始化的時候加載的,大家相互都認識。

  • 3)非靜態方法里面能不能引用靜態資源?可以,非靜態方法就是實例方法,那是實例化對象之后才產生的,那么屬于類的內容它都認識。

static 修飾類:這個用得相對比前面的用法少多了,static 一般情況下來說是不可以修飾類的, 如果 static 要修飾一個類,說明這個類是一個靜態內部類(注意 static 只能修飾一個內部類),也就是匿名內部類。像線程池 ThreadPoolExecutor 中的四種拒絕機制 CallerRunsPolicy、AbortPolicy、DiscardPolicy、 DiscardOldestPolicy 就是靜態內部類。靜態內部類相關內容會在寫內部類的時候專門講到。)

結論 6靜態成員函數

如果把函數成員聲明為靜態的,就可以把函數與類的任何特定對象獨立開來。靜態成員函數即使在類對象不存在的情況下也能被調用,靜態函數只要使用類名加范圍解析運算符?::?就可以訪問。

靜態成員函數只能訪問靜態成員數據、其他靜態成員函數和類外部的其他函數。

靜態成員函數有一個類范圍,他們不能訪問類的 this 指針。您可以使用靜態成員函數來判斷類的某些對象是否已被創建。

靜態成員函數與普通成員函數的區別:

  • 靜態成員函數沒有 this 指針,只能訪問靜態成員(包括靜態成員變量和靜態成員函數)。
  • 普通成員函數有 this 指針,可以訪問類中的任意成員;而靜態成員函數沒有 this 指針。

3.3 總結:

  • (1)靜態成員函數中不能調用非靜態成員。

  • (2)非靜態成員函數中可以調用靜態成員。因為靜態成員屬于類本身,在類的對象產生之前就已經存在了,所以在非靜態成員函數中是可以調用靜態成員的。

  • (3)靜態成員變量使用前必須先初始化(如 int MyClass::m_nNumber = 0;),否則會在 linker 時出錯。

一般總結:在類中,static 可以用來修飾靜態數據成員和靜態成員方法。

靜態數據成員

  • (1)靜態數據成員可以實現多個對象之間的數據共享,它是類的所有對象的共享成員,它在內存中只占一份空間,如果改變它的值,則各對象中這個數據成員的值都被改變。

  • (2)靜態數據成員是在程序開始運行時被分配空間,到程序結束之后才釋放,只要類中指定了靜態數據成員,即使不定義對象,也會為靜態數據成員分配空間。

  • (3)靜態數據成員可以被初始化,但是只能在類體外進行初始化,若未對靜態數據成員賦初值,則編譯器會自動為其初始化為 0。

  • (4)靜態數據成員既可以通過對象名引用,也可以通過類名引用。

靜態成員函數

  • (1)靜態成員函數和靜態數據成員一樣,他們都屬于類的靜態成員,而不是對象成員。

  • (2)非靜態成員函數有 this 指針,而靜態成員函數沒有 this 指針。

  • (3)靜態成員函數主要用來方位靜態數據成員而不能訪問非靜態成員。

再給一個利用類的靜態成員變量和函數的例子以加深理解,這個例子建立一個學生類,每個學生類的對象將組成一個雙向鏈表,用一個靜態成員變量記錄這個雙向鏈表的表頭,一個靜態成員函數輸出這個雙向鏈表。

實例

#include <stdio.h>
#include <string.h>
const int MAX_NAME_SIZE = 30;  class Student  
{  
public:  Student(char *pszName);~Student();
public:static void PrintfAllStudents();
private:  char    m_name[MAX_NAME_SIZE];  Student *next;Student *prev;static Student *m_head;
};  Student::Student(char *pszName)
{  strcpy(this->m_name, pszName);//建立雙向鏈表,新數據從鏈表頭部插入。this->next = m_head;this->prev = NULL;if (m_head != NULL)m_head->prev = this;m_head = this;  
}  Student::~Student ()//析構過程就是節點的脫離過程  
{  if (this == m_head) //該節點就是頭節點。{m_head = this->next;}else{this->prev->next = this->next;this->next->prev = this->prev;}
}  void Student::PrintfAllStudents()
{for (Student *p = m_head; p != NULL; p = p->next)printf("%s\n", p->m_name);
}Student* Student::m_head = NULL;  void main()  
{   Student studentA("AAA");Student studentB("BBB");Student studentC("CCC");Student studentD("DDD");Student student("MoreWindows");Student::PrintfAllStudents();
}

程序將輸出:

MoreWindows

DDD

CCC

BBB

AAA

?

總結

以上是生活随笔為你收集整理的【C++】C/C++ 中 static 的用法全局变量与局部变量的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。