1、定義在函式外面的變數是全域性變數
2、全域性變數具有全域性的生存期和作用域
3、它們與任何函式都無關
4、在任何函式內部都可以使用它們
上**
#include
intf
(void);
int gall =12;
intmain()
intf
(void
)
可以看到,全域性變數的改變與任何乙個函式都有關係
該**的列印結果為
1212
1414
變數gall先在main函式中列印在函式外初始化的值12,之後在f函式中先列印12,在加2之後,列印14,返回main函式的值也是14,這說明了:
全域性變數如其名,具有全域性的生存期和作用域,函式可以對它進行操作。確實很方便。
但要注意:
全域性變數的初始化
1、沒有做初始化的全域性變數會得到0值
2、全域性變數指標會得到null值
3、只能用編譯時已知的值來初始化全域性變數–>編譯之前就已確定的值 ,常量等
4、它們的初始化發生在main函式之前 -->也就是說它們的初始化值不能用函式中的值
#include
intf
(void);
int a;
int gall =12;
int*p;
intmain()
intf
(void
)
列印全域性變數a和p的值,會得到0,這說明了全域性變數,在沒有初始化之前,會被初始化為0。
tips:在函式外的陣列也會被初始化為0。
#include
int i =
3int a = i
intmain()
這樣的**是錯誤的,i雖然是乙個全域性變數,即使它被賦值了,它不能給全域性變數a賦值。因為在編譯時,編譯器並不知道i的值。它被視作乙個變數。
但如果:
#include
const
int i =
3int a = i
intmain()
在i前加上const,此時它被視作乙個確定的值(視作常量),因此a =3,編譯能夠通過。
1、在本地變數定義時加上static修飾符就成為靜態本地變數
2、當函式離開時,靜態本地變數會繼續存在並保持其值
3、靜態本地變數的初始化只會在第一次進入這個函式時做,以後進入函式時會保持上次離開的值
例如:
#include
intf()
intmain()
輸出結果為:24
4668
在main函式中呼叫了3次main函式,但a的值並沒有在每一次呼叫時發生變化,這就說明靜態本地變數的初始化只有在第一次進入這個函式時執行了,並且每次被呼叫時會保持上次的值。例如,在本例中,a在被呼叫時的值分別為2、4、6。
本地變數的位址與全域性變數不在一起存放。
1、靜態本地變數實際上是特殊的全域性變數
2.全域性變數和本地變數位於相同的儲存區域
3、靜態變數具有全域性的生存期,但作用域為乙個函式
4、static在這裡的意思是區域性作用域(本地可訪問)
例如:
#include
int a =3;
intmain()
輸出a、b、c的位址,會發現全域性變數a和靜態本地變數b位址相鄰,而本地變數c則在另一塊儲存單元上,這說明全域性變數和靜態本地變數型別相似,實際上,靜態本地變數是特殊的本地變數,只是作用域比本地變數小,只是它所在的那個函式。
1、返回本地變數的位址是不安全的–>本地變數的生存期只在函式內,存放本地變數的位址在使用後會被收回去,以供別的變數儲存值
2.返回全域性變數或本地變數的位址是安全的
3、返回在函式內malloc的記憶體是安全的,但是容易造成問題
4、最好的做法是返回傳入的指標(只改變傳入函式的那個值)
例如:
#include
int*f(
void);
voidg(
void);
intmain()
int*f(
void
)voidg(
void
)
在上述例子中,f()中的i變數位址所指的空間在函式呼叫結束後變得自由,以儲存下乙個變數,所以g()函式中的k佔據了這塊空間。用來儲存其值。所以,函式返回本地變數的位址是不安全的,因為你並不知道它是否還是你想要的那個值。
結構體是由一批資料組合而成的一種新的自定義型別。
內建型別不能表示所有的場景,比如:學生群體;描述學生:name、age、gender、height。
struct student
;
(1)為什麼需要記憶體對齊?
1、平台原因(移植原因):
不是所有的硬體平台都能訪問任意位址上的任意資料;某些硬體平台只能在某些位址處取某些特定型別的資料,否則丟擲硬體異常。
2、效能原因:
資料結構(尤其是棧)應該盡可能地在自然邊界上對齊;
原因在於,為了訪問未對齊的記憶體,處理器需要作兩次記憶體訪問,而對齊的記憶體訪問僅需要一次。
(2)如何進行記憶體對齊?
這裡分為兩大步驟:
1、使結構體中每個成員變數都處在對齊的位址上:
a、結構體中的第乙個成員變數在偏移量為0的位址上;
b、剩餘的變數,對齊規則:min(該變數型別,預設對齊數),然後檢測該變數相對於結構體起始位置的偏移量是不是該min的整數倍。不是的話,需要在該變數之前補齊位元組數。
2、讓結構體整體對齊:
使得結構體大小為 min(結構體成員變數型別最大者,預設對齊數)的最小整數倍。
(3)求結構體中某個成員變數相對於結構體起始位置的偏移量?
offsetof(結構體型別, 成員名字)
模擬實現該巨集:
#define offsetof(s, m) (size_t)&(((s*)0)->m)
//讓編譯器將0號位址單元開始的一塊記憶體作為s的結構體進行解析。
位段為一種資料結構,可以把資料以位的形式緊湊的儲存,並允許程式設計師對此結構的位進行操作。
位段的好處:
跟結構體相比,位段可以達到同樣的效果,但是可以很好的節省空間。
位段的缺點:
位段的記憶體分配與對齊的實現方式依賴於具體的機器和系統,在不同的平台可能有不同的結果,這導致了位段在本質上是不可移植的。
位段記憶體對齊:
a、前後型別相同,位元位能共用則共用,否則重新開闢對應型別的空間;
b、前後型別不一致,重新開闢空間。
聯合體也是一種特殊的自定義型別,這種型別定義的變數也包含一系列的成員,特徵是這些成員共用同一塊記憶體空間。
聯合的特點:
聯合的成員共用同一塊空間,這樣乙個聯合變數的大小,至少是最大成員的大小。
聯合大小的計算:
聯合的大小至少是最大成員的大小;
當最大成員大小不是最大對齊數的整數倍的時候,就到對齊到最大對齊數的整數倍。
為什麼有大小端?
因為在計算機系統中,我們是以位元組為單位的,每個地質單元都對應著乙個位元組,乙個位元組位8bit,但是在c語言中除了8bit的char之外,還有16bit的short、32bit的long(具體看編譯器),對於位數大於8位的處理器,由於暫存器大於乙個位元組,那麼必然存在乙個如何將多個位元組安排的問題,因此就導致了大端儲存模式和小端儲存模式。
大小端跟作業系統是否有關係?
跟作業系統沒有關係,cpu是大小端儲存的決定因素。
如何測試乙個機器為大端還是小端?
//利用聯合體判斷
intcheck_sys()
un; un.i =1;
return un.c;
}int
main()
else
system
("pause\n");
return0;
}
全域性變數和靜態全域性變數
全域性變數和區域性變數是從變數的作用域的角度劃分。靜態變數和動態變數是從變數的記憶體分配的角度劃分。全域性變數本身就是靜態儲存方式,靜態全域性變數當然也是靜態儲存方式。這兩者在儲存方式上並無不同,區別在於非靜態全域性變數的作用域是整個源程式,當乙個源程式由多個原始檔組成時,非靜態的全域性變數在各個原...
c 全域性變數 靜態全域性變數
全域性變數是靜態儲存方式,靜態全域性變數也是靜態儲存方式,這兩者在儲存方式上並無不同。區別 雖在於非靜態全域性變數的作用域是整個源程式,當乙個源程式由多個原始檔組成時,靜態全域性變數在各個原始檔中都是有效的。靜態區域性變數則限制了其作用域,只在定義該變數的原始檔內有效,在同一源程式的其它原始檔中不能...
C 全域性變數 靜態全域性變數 靜態區域性變數
全域性變數儲存在靜態儲存區,其作用域是全域性作用域,生命週期是整個程式的生命週期。具體而言,在乙個檔案中定義乙個全域性變數,在程式的其它檔案中可以通過extern關鍵字再次宣告說明該變數已經定義。靜態全域性變數儲存在靜態儲存區,其作用域只能是定義該變數的檔案,生命週期是整個程式的生命週期。靜態區域性...