指針、函數(shù)
1、const (相當(dāng)于java 的 final )
注意:const 放到誰的前面,誰不可改變。所以,<一般const的語法需要從右往左看,const修飾誰,誰就不可變>
const char *p; // 修飾的是 char 。所以 p 的內(nèi)容不可以修改,但是可以把p指向一個(gè)新的 char 的內(nèi)容地址
char const *p1; // 跟上面的 沒有 區(qū)別。因?yàn)閏onst 不可以修飾 * 符號,只能修飾char
char * const p2; // p2不可以改變,但是p2是一個(gè)指針,所以p2對應(yīng)的地址中的 內(nèi)容可以改變
const char * const p3; // p3的地址不可以改變,p3 的地址中的 char 內(nèi)容也不可以改變
2、多級指針
指向指針的指針
一個(gè)指針包含一個(gè)變量的地址。當(dāng)我們定義一個(gè)指向指針的指針時(shí),第一個(gè)指針包含了第二個(gè)指針的地址,第二個(gè)指針指向包含實(shí)際值的位置。
**存放的是其他指針的地址,所以下面代碼中 i 的地址和 j 的內(nèi)容是一樣的 **
int a = 10;
int *i = &a;
int **j = &i;
// 解引用
printf("i的地址是 %#x, j中存放的地址是 %#x\n", i, *j);
printf("j的地址是 %#x\n", j);
printf("j 解引用 數(shù)據(jù)是 %d\n", **j);
結(jié)果:
i的地址是 0xe129a528, j中存放的地址是 0xe129a528
j的地址是 0xe129a520
j 解引用 數(shù)據(jù)是 10
3、函數(shù)
函數(shù)參數(shù)
傳值調(diào)用
把參數(shù)的值 **復(fù)制** 給函數(shù)的形式參數(shù)。修改形參不會影響實(shí)參
引用調(diào)用
如果形參為指向 **實(shí)參地址的指針** ,可以通過指針修改 實(shí)參。
所以參數(shù)為指針的原因就是 為了 可以 修改 實(shí)參。不然得通過返回值,再次賦值給實(shí)參。
C 函數(shù)參數(shù) ~ 與 java 的區(qū)別
public void addition_isCorrect() {
int a = 10;
String str = "abcde";
Bean bean = new Bean();
change(a, str, bean);
System.out.println(str + " " + a + " " + bean);
}
public void change(int a, String str, Bean bean) {
a = 12;
str = "1344";
bean.age = 123;
bean.name = "345678";
}
class Bean{
int age = 100;
String name = "majie";
@Override
public String toString() {
return "Bean{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
結(jié)果: abcde 10 Bean{age=123, name='345678'}
int 和 String 沒有修改(傳值調(diào)用), Bean 類卻修改了其 屬性的值(類似引用調(diào)用)。
上面是java 的參數(shù)相關(guān)的代碼,下面是c的
void add(int a, int *b) {
printf("a 的值是 %d, b 的值是一個(gè)地址 %#x \n", a, b);
*b = a + *b;
printf("和值是 %d \n", *b);
}
void change(int **b) {
int ad = 1001;
// 因?yàn)閎是指針的指針,所以*b中是地址
*b = &ad;
// **b 表示的就是 對應(yīng)的地址中的數(shù)據(jù)
**b = ad;
}
int main(){
int c = 12;
int *f = &c;
printf("c 的值是 %d, f 的值是一個(gè)地址 %#x \n", c, f);
printf("add 調(diào)用之前 *f 是 %d \n", *f);
add(c, f);
printf("當(dāng)前的c是 %d, 當(dāng)前的 *f 是 %d \n", c, *f);
// 多級指針的意義 此時(shí) *f 的內(nèi)容是 24, 將 f 這個(gè)變量的地址,傳遞給 change 函數(shù)
change(&f);
printf("當(dāng)前的 *f 是 %d \n", *f);
return 0;
}
結(jié)果:
c 的值是 12, f 的值是一個(gè)地址 0xe0c23528
add 調(diào)用之前 *f 是 12
a 的值是 12, b 的值是一個(gè)地址 0xe0c23528
// add 方法中 f 和 b 是同一個(gè)地址,同時(shí)在add 方法中修改了 (*f) 的值
和值是 24
當(dāng)前的c是 24, 當(dāng)前的 *f 是 24
// 在change 方法中再次傳入 指針 f 的地址,同時(shí)修改了 指針f <指向的地址>,所以變成了 1001
當(dāng)前的 *f 是 1001
c中也有可變參數(shù),使用的是 ... 需要引入 #include<stdarg.h>
4、函數(shù)指針 ~ 指向函數(shù)的指針變量
C中可以接收一個(gè)函數(shù)作為參數(shù)
/**
* void (*p)(char *) 表示這個(gè)參數(shù)是一個(gè)函數(shù)
* void 表示 返回值
* char* 表示參數(shù)
* p 變量表示這個(gè)函數(shù)
* (*p) 表示 指向這個(gè)函數(shù)的 指針
*/
void say(void (*p)(char*), char *msg) {
p(msg);
}
void dayin(char *msg) {
printf("%s\n", msg);
}
int main()
{
// 聲明一個(gè)函數(shù)指針的變量,他指向了一個(gè)函數(shù) (這個(gè)變量的定義類別要跟這個(gè)函數(shù)一致)
void (*functionP)(char*) = dayin;
say(functionP, "niubi");
retutrn 0;
}
//typedef 創(chuàng)建別名 由編譯器執(zhí)行解釋
typedef void(*Callback)(int);
typedef long long int64_t; int64_t 就可以作為一個(gè) 類或者屬性來使用。 相當(dāng)于 long long 了
int number(int num) {
num = 1001 + num;
return num;
}
// 有點(diǎn)類似于 java 的回調(diào)或者接口
typedef int(*Callback)(int); // 此時(shí)Callback 就是一個(gè)別名,像類一樣,
int main() {
Callback call = number;
printf("num=%d\n", call(3));
return 0;
}