關於static的使用和函式中指標的一個認識誤區
在最初學習C語言函式時,我們就知道給函式傳參有兩種方法,一種是按值傳遞,另一種是按地址傳遞(傳指標)。
以swap函式為例:
void swap(int a,int b){
int temp=a;
a=b;
b=temp;
}
對於兩種傳參方式,效果一目瞭然。按值是單向傳遞,對實參生成副本,不直接操作main函式中的引數,因此不會交換main函式中引數的值。而如果傳指標,則直接對地址進行操作,能夠改變main函式中的引數。這時,我總會認為,main函式呼叫swap,傳遞了地址,而swap也確實改變了引數的值,因此傳遞指標呼叫函式,應該是雙向的,然而真的是這樣的嗎?
在學習指標時,老師留了一個作業,呼叫函式,用指向指標的指標的方法對整數進行排序,並在main函式中輸出排序後的整數。我們不去考慮這樣寫程式的實用性,僅僅是以應用學過的知識為目的去看這個程式碼,並從程式設計過程中遇到的問題來學習一些東西。
這是我最初寫的程式碼:
#include <stdio.h>
#define N 100
int **pp;
void sort(int n,int *p){
pp=&p;
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
if(*((*pp)+i)>*((*pp)+j)){
int temp=*((*pp)+i);
*((*pp)+i)=*((*pp)+j);
*((*pp)+j)=temp;
}
}
}
}
int main(){
int n;
int a[N];
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
}
sort(n,a);
for(int i=0;i<n;i++){
printf("%d ",*((*pp)+i));
}
return 0;
}
呼叫函式時,用指標p指向實參a的地址,因為題設要求用指向指標的指標,所以宣告pp指向p,而後操作pp進行排序。看似並沒有什麼問題,因為我在函式中直接操作的就是引數的地址,因此邏輯上沒有問題。但是除錯的時候,總會程式停止執行,那麼問題出在哪了呢?就出在 printf("%d ",*((*pp)+i)); 上了。
對於賦值語句:pp=&p; p確實指向了函式的地址,pp也確實指向了p的地址,而且pp也是全域性變數,但是,p是在函式形參,在函式呼叫結束之後,就消失了,這時,pp指向的地址就不存在了,因此,在輸出時會停止執行。
通常,我總會認為p和a是一樣的。實際上,a是一個地址常量,p是一個指向a的指標變數,在函式作用域內有效,函式並沒有返還給main函式東西,因此實際上即使是按指標傳遞變數,仍然是單向傳遞
那麼對於這道題,怎麼解決這個問題呢?關鍵就在讓pp指向的值不失效,一個辦法就是將p宣告為static靜態型別,這樣就能不受函式限制而一直存在:
#include <stdio.h>
#define N 100
int **pp;
void sort(int n,int a[]){
static int *p=a;
pp=&p;
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
if(*((*pp)+i)>*((*pp)+j)){
int temp=*((*pp)+i);
*((*pp)+i)=*((*pp)+j);
*((*pp)+j)=temp;
}
}
}
}
int main(){
int n;
int a[N];
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
}
sort(n,a);
for(int i=0;i<n;i++){
printf("%d ",*((*pp)+i));
}
return 0;
}