全局變量
全局變量:定義在函數體外部(包括main函數)的變量。全局變量的作用域是本文件,在其它文件要使用這個變量需要重新聲明。
- 使用 extern 關鍵字聲明另一個文件定義的全局變量。
extern int global; //聲明一個全局變量。相當於告訴編譯器,你別管啦,這是個全局變量,我保證他是存在的。
- 全局變量有風險,謹慎定義,因為任何人都能修改它的值。
static int global = 200; //全局靜態變量(靜態的只允許本文件內部訪問)
- 全局變量的生命周期是整個程序運行期間。全局變量沒有初始化時,其值為0,浮點型是0.0,布爾類型是false(0)
局部變量
1)定義在函數內部(包括:函數的參數、if、for、while里面定義的變量)
2)定義在復合語句(代碼塊{……})中
- 默認的局部變量(也叫自動變量):
auto int a; //由關鍵字auto聲明,可以省略。內存空間是自動分配,(出了作用域)自動釋放!
- 靜態局部變量:
static int a; //變量a在全局區分配空間,函數結束時候,內存不會釋放。
※ 不管調用函數多少次,這條語句只執行一次,即第一次執行,內存空間不受函數的控制。
※ 靜態局部變量的生命周期和全局變量一樣,都是整個程序運行期間!
※ 局部變量在沒有初始化的情況下是一個隨機數據(垃圾值)
auto關鍵字
auto int x;//自動變量,局部變量(auto默認省略)
auto 只能修飾局部變量,不能修飾全局變量!
static關鍵字
1. 修飾局部變量:生命周期變長(整個程序運行期間),作用域不變(和普通變量一樣)
static修飾的局部變量,其數值就是上一次函數調用結束之后的數值!
擴展(用途):可以記錄一個函數被調用了多少次!
//計數器函數,記錄被調用的次數 int count() { static int cnt = 0; //不管調用多少次函數,這條語句只會執行一次 cnt++; return cnt; } |
2. 修飾全局變量:只能在本文件內部訪問,其它文件不能訪問。保護全局變量。
//靜態的只允許本文件內部訪問
static int global = 200;//全局靜態變量
3. 修飾函數:也是只能在本文件中訪問,其它文件都不能訪問!
//此函數為私有函數,只允許本文件內部調用,別的文件中無法調用
static void func(){
printf("這是本文件內部函數,其它文件中無法調用!\n");
}
舉例:使用static修飾局部變量,查看特性。
對比之下,可以看出使用static修飾的局部變量的特性,訪問范圍和普通的局部變量一樣,但是在函數執行完畢之后其數值並不會釋放。
const關鍵字
const修飾的變量:只讀變量(常量),不可修改變量的數值!
register、volatile
//寄存器變量,僅僅是申請一下,編譯器不一定批准 register int x = 10;//CPU, 理論上存取速度非常快 //易變的變量,編譯器讀取時不要做優化處理,除非在嵌入式開發中使用傳感器改變變量的值時 volatile int y = 20; |
使用 extern 關鍵詞聲明另一個文件定義的全局變量
extern int global; //聲明一個全局變量。相當於告訴編譯器,你別管啦,這是個全局變量,我保證他是存在的。
extern void sum(); //外部函數的聲明。
static void minus(); //內部函數的聲明
字符串面試題
/** * 實現字符串常用的4個庫函數 */ #include <stdio.h> #include <assert.h> /** 實現strlen函數 */ int mystrlen(char *arr) { int count = 0;//定義變量記錄取出了多少個字符 while(arr[count] != '\0') { count++; } return count; } /** 實現strcat函數 */ char *mystrcat(char *str1, const char *str2) { char *tmp = str1; while(*str1) str1++; while((*str1++ = *str2++) != '\0'); return tmp; } /** 實現strcpy函數 */ char *mystrcpy(char *str1, const char *str2) { assert(str1 != NULL && str2 != NULL);//斷言函數,檢查參數的有效性(防錯設計) char *tmp = str1; //*str2對*str1逐個字符進行賦值 //*str2直到把'\0'賦值給*str1時,*str1的結果就是0,循環就結束! while((*str1++ = *str2++)); return tmp; } /** 實現strcmp函數 */ int mystrcmp(char *str1, char *str2) { assert(str1 != NULL && str2 != NULL); while(*str1 == *str2 && *str1 != '\0') str1++, str2++; if(*str1 > *str2) { return 1; } else if(*str1 < *str2) { return -1; } else { return 0; } } int main() { char str1[] = "hello"; char *str2 = "world"; printf("%d\n", mystrlen(str1));//str1的長度為:5 printf("%s\n", mystrcat(str1, str2));//拼接后:helloworld printf("%s\n", mystrcpy(str1, "ABCDE"));//拷貝(覆蓋):ABCDEF printf("%d\n", mystrcmp(str1, str2)); //-1(str1 < str2) return 0; } |
//字符串賦值(拷貝) void Strcpy(char *s1, const char *s2) { //while(*s1++ = *s2++); while (*s2 != '\0') { *s1 = *s2; s1++; s2++; } *s1 = '\0'; } //字符串連接 void Strcat(char *s1, const char *s2) { while(*s1)s1++; //while(*s1++ = *s2++); while(*s2){ *s1 = *s2; s1++; s2++; } *s1 = 0; } //字符串長度 int Strlen(const char *str) { int cnt = 0;//保存結果 while (*str) { cnt++; str++; } return cnt; } //字符串比較 int Strcmp(const char *s1, const char *s2) { while(*s1 || *s2){ if(*s1 > *s2) return 1; else if(*s1 < *s2) return -1; s1++; s2++; } return 0; } |
有一個字符串"abcd1234",請寫一個函數,將此字符串拆成兩部分, abcd保存到char str[10]中,1234保存到變量int x中: int str2int(char *str, char *s){ //.... } int main() { char *source = "abcd1234"; char str[10] = {0}; int x = 0; x = str2int(cource, str); } |