@[toc]
學生時代所學的一些 C 語言知識點回顧(2)——指針
一 前言
承接上一篇,對 C 語言中的指針進行了回顧總結。文中的例子均為本人純手工輸入,在 Linux 環境中全部編譯實踐過。由于平時工作中大部分時間都使用 Linux ,許多深入的 Linux 體系知識需要掌握 C 語言才能深入地了解,故此,對 C 語言進行了一次回顧。工作多年以後,才發現:曾經所學的一切知識并非一無是處,而是那時的自己太粗淺,太急功近利。就像 C 語言,在目前的工作中仍能發揮重大作用,時常能起到事半功倍的效果。關于這些,在後期我的分享中将會完美呈現,敬請關注。
二 一些例子
# include<stdio.h>
int main(int argc,char *argv[]){
int i = 10, j, *p, *q, *x = &i;
p = &i;
q = p;
j = *&i;
printf("p = %d\n",*p);
printf("q = %d\n",*q);
printf("x = %d\n",*x);
printf("j = %d\n",j);
scanf("%d",&i);
printf("p = %d\n",*p);
printf("q = %d\n",*q);
printf("x = %d\n",*x);
printf("j = %d\n",j);
return 0;
}
/*
p = 10
q = 10
x = 10
j = 10
98
p = 98
q = 98
x = 98
j = 10
*/
這個例子種,指針變量 x 在聲明的同時進行了初始化工作,這種操作是合法的。在聲明之後再進行初始化則需要以類似于指針變量 p 的方式進行初始化,仍然使用 *p = &i 這種聲明方式是無法通過編譯的。
通過 *p 這種方式使用指針值叫做間接尋址。此處的 * 稱之為間接尋址運算符。
多個指針變量指向同一變量時,該變量的值改變之後,指針變量的值也随之改變。
*&i 對變量 i 使用 & 運算符産生指向指針變量的指針,對指針使用 * 運算符則可以傳回到原始變量。
# include<stdio.h>
int main(int argc,char *argv[]){
int *p, *q, i = 989, j = 2019;
p = &i;
q = &j;
q = p;
printf("p = %d\n",*p);
printf("p : %p\n",p);
printf("j = %d\n",j);
printf("q = %d\n",*q);
printf("q : %p\n",q);
return 0;
}
/*
p = 989
p : 0x7fff51751e5c
j = 2019
q = 989
q : 0x7fff51751e5c
*/
同類型的指針變量可以互相複制,複制之後指向同一變量。
# include<stdio.h>
int main(int argc,char *argv[]){
int *p, *q, i = 989, j = 2019;
p = &i;
q = &j;
*q = *p;
printf("p = %d\n",*p);
printf("p : %p\n",p);
printf("j = %d\n",j);
printf("q = %d\n",*q);
printf("q : %p\n",q);
return 0;
}
/*
p = 989
p : 0x7ffc00d359ac
j = 989
q = 989
q : 0x7ffc00d359a8
*/
這段代碼看起來跟上一段十分相似,但是運作結果卻截然不同。指派語句 q = p 把指針變量 p 的值複制到 q 指向的對象中,也就是 j 中,但是 p 和 q 的位址是不一樣的。
# include<stdio.h>
int main(int argc,char *argv[]){
char i, *p;
p = &i;
scanf("%c",p);
printf("p = %c\n",*p);
printf("i = %c\n",i);
return 0;
}
/*
e
p = e
i = e
*/
在這一段代碼中,如果删除 “p = &i;” 這一句,那麼這段代碼是不能順利通過編譯的,函數 scanf() 中的 變量 p 就相當于 &i, scanf() 讀入的字元并存儲于 i 中。此時,scanf() 中不能再使用運算符 &。
# include<stdio.h>
int main(int argc,char *argv[]){
int a, b;
int *max(int *,int *);
scanf("%d%d",&a,&b);
printf("The max number is: %d\n",*max(&a,&b));
return 0;
}
int *max(int *a, int *b){
*a = *a + 5;
if (*a > *b)
return a;
else
return b;
}
/*
1 4
The max number is: 6
*/
指針變量作為形參進行傳遞、運算,并函數的傳回值類型為指針。再繼續看下一段代碼:
# include<stdio.h>
int main(int argc,char *argv[]){
int a, b;
int max(int *,int *);
scanf("%d%d",&a,&b);
printf("The max number is: %d\n",max(&a,&b));
return 0;
}
int max(int *a, int *b){
*a = *a + 5;
if (*a > *b)
return *a;
else
return *b;
}
/*
1 4
The max number is: 6
*/
同樣的輸入,一樣的輸出結果,形式不一樣,實際上實作原理也是一樣的,都傳回指針,可以類比來了解。
# include<stdio.h>
int main(int argc,char *argv[]){
int x = 2019, y=2023;
int *a = &x, *b = &y, c;
c = (*a + *b) * 2 + 20;
printf("Sum: %d\n",c);
return 0;
}
// Sum: 8104
以上代碼的第4行和第5行互換,将不能通過編譯。C 語言嚴格遵循先聲明後使用的原則,指針也不例外。間接尋址在表達式中是可以直接使用的。需要說明的是:“int *a = &x, *b = &y, c;”這一行中的 * 不是間接尋址運算符,其作用是告知編譯器 a 和 b 是兩個指向 int 類型變量的指針。 “c = (*a + *b) * 2 + 20;”這一行的前兩個 * 是間接尋址運算符,第三個 * 是乘法運算符。
# include<stdio.h>
int main(int argc,char *argv[]){
int p;
int example(int *);
scanf("%d",&p);
printf("%d\n",example(&p));
return 0;
}
int example(int *p){
int a = 10086;
printf("The original value is: %d\n",*p);
p = &a;
return *p;
}
# include<stdio.h>
int main(int argc,char *argv[]){
int p;
int example(int *);
scanf("%d",&p);
printf("%d\n",example(&p));
return 0;
}
int example(int *p){
printf("The original value is: %d\n",*p);
*p = 10086;
return *p;
}
# include<stdio.h>
int main(int argc,char *argv[]){
int p;
int example(const int *);
scanf("%d",&p);
printf("%d\n",example(&p));
return 0;
}
int example(const int *p){
int x = 10086;
printf("The original value is: %d\n",*p);
p = &x;
return *p;
}
/*
98
The original value is: 98
10086
*/
以上三段代碼編譯執行後均能得到一緻的結果,但是如下代碼卻不能通過編譯:
# include<stdio.h>
int main(int argc,char *argv[]){
int p;
int example(const int *);
scanf("%d",&p);
printf("%d\n",example(&p));
return 0;
}
int example(const int *p){
printf("The original value is: %d\n",*p);
*p = 10086;
return *p;
}
這說明使用了 const 關鍵字之後,不能改變指針指向的整數,但是能改變指針自身。因為實參是按值進行傳遞的,是以通過指針指向其他地方的方法給 p 賦新值不會對函數外部産生任何影響。在聲明時,關鍵字 const 是不能省略的。繼續看下面的代碼。
# include<stdio.h>
int main(int argc,char *argv[]){
int p;
int example(int * const);
scanf("%d",&p);
printf("%d\n",example(&p));
return 0;
}
int example(int * const p){
printf("The original value is: %d\n",*p);
*p = 10086;
// int x = 10086;
// p = &x;
return *p;
}
/*
98
The original value is: 98
10086
*/
本段代碼中,如果取消注釋部分,則不能通過編譯。在此處,可以改變指針指向的整數,但是不能改變改變指針自身。進一步嘗試:
# include<stdio.h>
int main(int argc,char *argv[]){
int p;
int example(const int * const);
scanf("%d",&p);
printf("%d\n",example(&p));
return 0;
}
int example(const int * const p){
printf("The original value is: %d\n",*p);
// *p = 10086;
// int x = 10086;
// p = &x;
return *p;
}
/*
98
The original value is: 98
98
*/
本段代碼中出現了兩個 const 關鍵字。代碼中被注釋的3行,取消任意一部分均不能通過編譯。這種情況說明:通過這種聲明之後,既不能改變指針指向的整數,也不能改變指針自身。不過這種情況比較少見。
三 小結
此部分主要回顧了指針,使用了較長篇幅驗證了 const 關鍵字,可能還存在較多了解上的誤區,希望各位多多指點、溝通交流,彼此進步。