全局變量和宏

全局變量

即定義在所有函數之外(一般都定義在main函數之前,#include頭文件下邊)的變量,這個是與局部變量(本地變量)所不同的,它可以在任何函數中使用

下面舉個例子

1

# include <stdio.h>

int i;
int * p;

int main(void) {
	
	printf("全局變量 i 的值爲%d\n", i);
	printf("全局變量 p 的值爲%s\n", p);
	
	return 0; 
}

輸出結果爲:

 

沒有初始化的全局變量會被賦予0這個值,如果是指針,會被賦予NULL這點通過上面程序的結果即可發現;對全局變量進行初始化時,最好直接用編譯時刻已知的值(即數字或常變量等),但最好只是用數字而不要使用其他方法

它的初始化發生在main函數之前

如果在函數內部有變量與全局變量名相同,則在該函數中,全局變量會被覆蓋

2

# include <stdio.h>

int i;
//int * p;
void f();

int main(void) {
	i = 9;
	
	printf("在%s函數中 i 的值爲%d\n", __func__, i);
//	printf("全局變量 p 的值爲%s\n", p);
	f();
	
	return 0; 
}

void f() {
	int i = 3;
	printf("在%s函數中 i 的值爲%d\n", __func__, i);
}

輸出結果爲:

 

由上結果可以證明

另外,通過上面的例子可以發現,printf中放一個 %s ,而再輸出的後面,對應的加一個__func__,則會輸出該語句所在的函數的名字


上面的例子是在局部函數中定義相同變量名,覆蓋了全局變量,下面舉個全局變量的使用範圍例子


3

# include <stdio.h>

int i;
//int * p;
void k(); 
void f();

int main(void) {
	i = 9;
	
	printf("在%s函數中 i 的值爲%d\n", __func__, i);
//	printf("全局變量 p 的值爲%s\n", p);
	f();
	printf("在%s函數中 i 的值爲%d\n", __func__, i);
	
	return 0; 
}

void f() {
//	int i = 3;
	printf("在%s函數中 i 的值爲%d\n", __func__, i);
	k();
	printf("在%s函數中 i 的值爲%d\n", __func__, i);
}

void k() {
	i = 1000;
	printf("在%s函數中 i 的值爲%d\n", __func__, i);
}

輸出結果爲:

 

靜態局部變量

就是在定義局部變量時在其類型前邊加上static修飾符

當函數離開時,靜態局部變量會繼續存在(不會被釋放內存)並保持其值

靜態局部變量的初始化只會在第一次進入這個函數時做,以後進入此函數時會保持上次離開的值

舉例說明

4

# include <stdio.h>

int i;
//int * p;
void f(int);

int main(void) {
	i = 9;
	
	printf("在%s函數中 i 的值爲%d\n", __func__, i);
//	printf("全局變量 p 的值爲%s\n", p);
	f(i);
	
	i += 1;
	printf("在%s函數中,改變後的 i 的值爲%d\n", __func__, i);
	f(i);
	
	return 0; 
}

void f(int t) {
	static int s = t;
	printf("在%s函數中 s 的值爲%d\n", __func__, s);
}

輸出結果爲:

 

由上可以發現,第一次i的值爲9時,將其傳入f函數中,賦值給static int 變量s,輸出s的值也爲9,而當i的值改變爲10時,再次傳入f函數,將其值賦給s,但輸出的s的值仍爲9


下面再試一下,看靜態變量、全局變量和局部變量分配的內存的地址在哪兒

5

# include <stdio.h>

int i;
//int * p;
void f(int);

int main(void) {
	i = 9;
	
	printf("在%s函數中 i 的值爲%d\n", __func__, i);
//	printf("全局變量 p 的值爲%s\n", p);
	f(i);
	
	i += 1;
	printf("在%s函數中,改變後的 i 的值爲%d\n", __func__, i);
	f(i);
	
	return 0; 
}

void f(int t) {
	int j = 0;
	static int s = t; 
	printf("全局變量i的地址爲:      &i = %p\n", &i);
	printf("局部靜態變量的s地址爲:  &s = %p\n", &s);
	printf("局部變量j的地址爲:      &j = %p\n", &j);
	printf("在%s函數中 s 的值爲%d\n", __func__, s);
}

輸出結果爲:

 

由上面的結果可以發現,局部靜態變量的地址有很大差距,而它反而和全局變量分配的內存的地址相近,說明靜態局部變量實際上是特殊的全局變量,而且它們位於相同的內存區域,static在這裏是局部作用域的意思,即其函數內部可訪問

#開頭的是編譯預處理指令,它不是C語言的語句,但它是不可或缺的

#define是定義了一個宏,下面給出格式:

#define 名字 值

這三者之間只有兩個空格,值的後邊沒有空格,不要加,不然很可能出錯

注意,結尾是沒有分號的,因爲它不是語句,名字必須是單詞或字母,值可以隨意(數字表達式皆可)

它是在編譯器進行編譯之前被處理的


下面舉個例子

6

# include <stdio.h>
# define N 5

int main(void) {
  int a = 10;
  
  printf("a*N=%d\n", a * N); 
	
	return 0;
}

輸出結果爲:

 

由上可知,N的值爲5,宏就是這樣,通過#define,讓N5等價,即在下面的程序中凡是出現N的地方,可以將它替換成5,這樣做,是爲了在寫較大的程序時,使用一些數字,或許可能遺忘數字的含義,所以起一個名字替換該數字,而且,要是多次用到該數字,如果想改,需要在代碼中一個個的找到,然後修改,使用宏以後,只需在程序最前邊修改一次即可(注:宏定義一般是大寫的字母或單詞)


如果一個宏的值中有其它的宏,已久會被替換

如果一個宏的值超過一行,最後需要加\

宏後面出現的註釋不會被替換 

宏不單單可以定義數字,也可以定義表達式,但定義表達式時需要注意一點,首先舉個例子

7

# include <stdio.h>
# define S "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
ssssssssssssssssssssss" //這是定義一個字符串,沒什麼用,只爲舉例 說明 
# define M 3
# define N 2
# define Q M+N  //這幾個宏的值沒什麼用,只爲舉例說明 

int main(void) {
	int a = 10;
  
  	printf("Q=%d\n", Q); 
    printf("Q*Q=%d\n", Q*Q);
    printf("S=%s\n", S);
	
	return 0;
}

輸出結果爲:

 

請看下面的輸出結果,Q*Q按說應該是5*5=25,但結果卻是11?這是因爲,它是這麼算的Q=M+N,則Q*Q=M+N*M+N,即3+2*3+2,結果爲11,要向達到預期效果,定義第三個宏時後面需要加括號

當然,這只是個簡單的例子,實際上可以進一步的延伸,這裏就不多說了


除了自己定義宏之外,還有一些預定義宏(不需要我們再定義了),如:__FILE____LINE____DATE____TIME__ (注意:它們的兩邊都是兩個下劃線 

這些都是什麼意思呢?

舉個例子

8

# include <stdio.h>

int main(void) {

  	printf("__FILE__是:%s\n", __FILE__); 
  	printf("__LINE__是:%d\n", __LINE__); 
  	printf("__DATE__是:%s\n", __DATE__); 
  	printf("__TIME__是:%s\n", __TIME__); 
	
	return 0;
}

輸出結果爲:

 

由結果可推測一下(其實第二個也未必能猜出),第一個是源程序文件的路徑

第二個是該行代碼所在的行號,第三個是輸出日期,第四個是輸出當前時間


其實,還可以定義帶參數的宏,這個用起來也有點兒像函數

帶參數的宏一定要加括號,整個值也要加括號,每個參數出現的地方都要加括號

例:9

# include <stdio.h>
# define max(a,b) (a>b?a:b) //後邊是表達式的話,最好帶着括號 

int main(void) {
	int i = 4, j = 7;  //僅僅是舉例 
	printf("較大的數爲:%d\n", max(i,j));
	
	return 0;
}

輸出結果爲:

 

這是個帶參數的宏,它的後邊是一個三目運算符,表示ab兩個值中的較大的數,看printf中的max(i,j),是不是像個函數調用?其實這裏功能一樣


【所有代碼均在windows系統下dev c++下運行通過】

(如有錯誤,敬請指正)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章