### 指針數組
指針數組里的每個存儲區都是一個指針類型的存儲區。
字符指針數組包含多個字符指針,每個字符指針都可以用來表示一個字符串。
字符指針數組可以用來代表多個相關字符串。
#include <stdio.h>
int main(){
char *strs[] = {"abc", "def", "iop", "asd", "xyz"};
int num = 0;
for (num =0;num <= 4;num++){
printf("%s\n", strs[num]);
}
return 0;
}
二維字符數組也可以用來記錄多個相關字符串。
通常采用字符指針數組表示多個相關字符串。
### 宏定義
`#define`預處理指令用來定義宏
宏可以用來給數字起名字。
#include <stdio.h>
#define PI 3.14 // 宏定義
int main(){
int radius = 0;
printf("請輸入半徑: ");
scanf("%d", &radius);
printf("周長是:%g\n", 2 * PI * radius);
return 0;
}
宏定義語句里宏名稱寫在前面,它代表的數字寫在后面。
宏名稱通常由大寫字母構成。
宏名稱里不能包含空格。
用宏給數字起名字的時候,不要使用賦值操作符。
編譯器在編譯的時候會首先把程序里的宏名稱替換成它代表的數字。
### gcc編譯
使用gcc -E可以查看預處理后的結果:
gcc -E main.c
可以在編譯命令里使用-D的選項指定宏代表的數字。
#include <stdio.h>
// #define PI 3.14
int main(){
int radius = 0;
printf("請輸入半徑: ");
scanf("%d", &radius);
printf("周長是:%g\n", 2 * PI * radius);
return 0;
}
gcc進行編譯:
gcc -DPI=3.14f main.c
如果程序中某些數字在編寫的時候無法確定,只能在編譯的時候才知道就可以使用宏名稱代表它們,使用-D命令來進行從外面編譯宏數據。
### 宏計算公式
宏也可以給計算公式起名字。
計算公式里包含未知數字,宏的參數用來代表這些未知數字。
### 宏參數
帶參數的宏采用二次替換的方式進行處理。
宏的參數不一定代表數字,所以沒有類型名稱。
如果宏有多個參數就需要在相鄰的參數名稱之間用逗號把他們分開。
宏因為不會被分配存儲區,所以沒有可以使用自己的存儲區和函數進行數據傳遞。
宏沒有形式參數也沒有用來存放返回值的存儲區。
能當數字使用的宏,必須是邏輯表達式(因為宏沒有用來存放返回值的存儲區)。
#include <stdio.h>
#define ABS(n) n >= 0 ? n : 0 - n
#define NEG(n) n = n - n
int main(){
int num = 0;
printf("請輸入一個數字:");
scanf("%d", &num);
printf("絕對值是: %d\n", ABS(num));
return 0;
}
宏的參數直接代表的就是函數的存儲區,對宏參數內容的修改直接修改的就是函數存儲區的內容。
### 宏計算的優先級
因為宏沒有用來記錄返回值的存儲區,所以不能保證優先計算宏內部的操作符。
能當做數字使用的宏必須寫在一對小括號中間。
正確寫法:
#include <stdio.h>
#define SUB(x, y) ((x) - (y))
int main(){
printf("SUB(x, y) = %d\n", SUB(10, 5));
printf("20 - SUB(x, y) = %d\n", 20 - SUB(10, 5));
return 0;
}
宏沒有形式參數所以不能保證優先計算參數里面的操作符。
宏的所有能代表數字的參數,必須都寫在小括號里面。
#define SUB(x, y) ((x) - (y))
不要使用自增或者自減的結果作為宏的參數。
#include <stdio.h>
#define SQUARE(n) ((n) * (n))
int main(){
int num = 5;
printf("SQUARE(n) = %d\n", SQUARE(5));
printf("SQUARE(++num) = %d\n", SQUARE(++num));
return 0;
}
### 宏操作符
編寫宏的時候可以使用一些特殊的操作符,他們叫做宏操作符。
**# 操作符**
`#`是一個宏操作符,它可以把宏的一個參數轉換成字符串字面值。
#include <stdio.h>
#define STR(n) #n
int main(){
STR(2 + 4); // "2 + 4"
return 0;
}
**## 操作符**
`##`也是一個宏操作符,它可以把一個代表標識符的參數和其他內容鏈接成為一個新的標識符。
#include <stdio.h>
#define PTR(n) p_##n
int main(){
int num = 0;
int *PTR(num) = #
return 0;
}
### 條件編譯
**#ifdef/$ifndef...#else...#endif**
條件編譯可以在編譯的時候從幾組語句中選擇一組編譯而忽略其他組。
`#ifdef/$ifndef...#else...#endif`,這種結構可以根據一個宏是否被定義過從兩組語句中選擇一組編譯。
以上兩種結構,最開始的預處理指令,需要從兩個選擇一個,不論選哪個后面都要跟一個宏名稱。
如果最前面的預處理執行時`#ifdef`就表示它后面的宏名稱被定義過的時候編譯前一組語句,否則編譯后一組語句。
如果是`#ifndef`則相反。
/*
條件編譯演示
*/
#include <stdio.h>
int main(){
#ifdef YI
printf("1\n");
#else
printf("2\n");
#endif
return 0;
}
YI是一個宏,當我們在編譯的時候沒有去編譯這個宏,則會打印出2,否則就是1。
#ifndef 反之
**#if...#elif(任意多次)...#else...#endif**
`#if...#elif(任意多次)...#else...#endif`,這種結構也可以實現條件編譯,它可以根據任意邏輯表達式從多組語句中選擇一組編譯而忽略其他組。
/*
條件編譯演示
*/
#include <stdio.h>
int main(){
#if defined(JINGPIN) // defined的意思是確認宏是否被定義,定義了則為真,沒定義則
為假
printf("120%%\n");
#elif !defined(JINGPIN) && !defined(GONGCHANG)
printf("100%%\n");
#else
printf("80%%\n");
#endif
return 0;
}