——關於指針的一個問題
今天班上的一位學霸在學習數據結構的字符串的時候遇到了一個問題,這個問題就是他在寫代碼的時候,不管怎麼樣主函數裏就是不能夠給指針賦值,就算賦值了好像指針裏啥都沒有,更別說使用其他函數了。
首先聲明一下:這個問題其實並不難,個人認爲這個問題只要簡單的認識兩個點——指針到底是什麼?指針到底怎麼用?就可以搞懂這個問題了!接下來我會用我認爲最簡單的思路爲有疑惑的同學一步步的講解,希望各位有耐心的看完,謝謝!!!
話不多說,我模擬了一下當時重要部分的代碼,具體如下:
void output(char *chars){
int i = 0;
while(chars[i]!='\0'){
printf("%c",chars[i]);
i++;
}
}
int main(){
//char chars[] = "abcdefg";
char *chars;
int i = 0;
while(scanf("%c",&chars[i++])!='\0'){}
output(chars);
return 0;
}
代碼分析
1、從上述代碼可以看出,output中的一個參數是char的指針,output這個函數目的就是簡單的輸出一下指針裏的東西。
2、主函數中定義了一個名字爲chars的字符串指針,並且主函數中試圖利用循環對指針進行賦值。
3、主函數對名爲chars的指針賦值完畢之後,最後調用output函數將指針的值輸出。
沒錯,你沒有看錯,就是這麼簡單的代碼!好了,最上述代碼的具體功能分析已經結束。
問題分析 & 問題解決
我們再看一下問題:主函數不能給chars這個指針賦值,在運行的時候就是輸入一串字符之後就中止進程了,就像這樣👇:
那麼這種問題爲什麼會出現?其實仔細看代碼,其他地方實際上都沒有寫錯,就是這個chars怎麼看都不順眼(實際上當時不是while循環是for循環,當時for循環也有一點小問題,所以這裏寫成了while)
當時是指針的錯誤,但是我沒有急着說,我在想什麼同學會這樣寫——主函數中有一個chars的指針,output函數中的參數也爲chars指針。沒錯,許多人都有個習慣,那就是認爲主函數中要調用自定義函數,那麼傳過去東西的也必須是和自定義函數一樣的(都是指針)!這是我的同學犯錯的原因之一。
不急着矯正錯誤,如果順着其思路走下去,其實想法是沒錯的。因爲在學數據結構的時候有個順序表,順序表中有個內容是這樣的👇:
第一部分
//順序表數據結構
typedef struct SqList{
Book *elem; //儲存空間的基地址
int length; //數據結構的長度
};
第二部分:
//初始化順序表基本算法
Status InitList(SqList &BookSystem){
//構造一個空的順序表BookSystem
BookSystem.elem = new Book[maxsize]; //分配內存空間
if(!BookSystem.elem)exit(-1); //存儲分配失敗
BookSystem.length = 0; //當前長度爲0
return OK;
}
第三部分:
//添加6本圖書
void insertBook(SqList &BookSystem){
int i = 0; //循環變量
for(i;i<6;i++){
int index = i;
Book newBook;
scanf("%s %s %s %s %s %f",&newBook.isbn,&newBook.authorName,
&newBook.bookName,&newBook.publisher,
&newBook.publishYear,&newBook.price);
BookSystem.elem[index] = newBook;
}
}
當時他說有個地方搞不清,就是結構體中的elem也是個指針,在insertBook函數中也可以用下標形式給指針賦值,所以就按照這個思路寫了他的代碼。
乍一看好像也對,但仔細看看就不對了,我相信我的同學沒有仔細揣摩爲什麼要有第二部分,而是直接照着第一部分和第三部分寫了代碼。沒有理解到初始化指針的作用,這也是我的同學犯錯的原因之二。
問題解決之指針到底是什麼?指針的作用方式?
知道了錯誤之後,就要糾正錯誤,糾正錯誤就從兩點搞起:1、指針到底是個啥?2、指針到底咋個用?——接下來就以我自己的想法和大家說一說,也許就能解決大家的疑惑了!
首先,指針是個啥?我們都知道指針這東西很重要,這東西就想駭客手裏的工具一樣,“指”到你的設備,就能入侵你的設備並且還能扒取並修改你設備裏的信息,但如果不去“指”,這個工具就缺少了入侵別人設備的途徑,也就不能對別人的設備爲所欲爲了。
上面已經說了指針必須得指到一個東西才能改那個東西。那麼看上面代碼可以知道,光定義了一個指針,但是沒把任何東西的地址給那個指針,那還怎麼能給那個指針賦值呢?這就是犯錯的第二個原因,沒有初始化指針!
這裏繼續強調一下第二個代碼示例中的第二部分,第二部分中將Book數組的首元素地址給了elem指針,所以才能執行第三部分的添加圖書的操作的👇
BookSystem.elem = new Book[maxsize]; //分配內存空間
好了,到了這裏肯定有人會認爲:給主函數裏的那個指針一個被指的東西不就好了?就像這樣👇:
int main(){
char shuzu[] = "abcdefg";
char *chars = shuzu;
int i = 0;
while(scanf("%c",&chars[i++])!='\0'){}
output(chars);
return 0;
}
確實,給一個字符數組讓指針去指,就可以通過指針給數組賦值了。但還是有一個問題——主函數中調用output函數時傳的是指針嗎?顯而易見,肯定不是,與上面所說的一樣,指針通過指向某個值之後再去獲取或修改那個值。再看下面的代碼👇:
void output(char *chars){
//輸出數組內容...
}
int main(){
//代碼略...
output(chars);
return 0;
}
主函數傳了個指針chars給output函數,output函數接收到chars之後,chars指向了chars然後執行輸出操作,兩者都是指針。聽着是不是很亂?還記得我說的犯錯的原因之一是什麼嗎?就是取了相同的名字所以容易讓人混淆!
我們將主函數中的chars改個名👇:
void output(char *chars){
//輸出數組內容...
}
int main(){
char shuzu[] = "abcdefg";
char *c = shuzu;
int i = 0;
while(scanf("%c",&c[i++])!='\0'){}
output(c);
return 0;
}
output函數接收到c之後,chars指向了c,如果說chars要取數組的內容那麼是這樣的:指針chars去找指針c中所指的數組的元素。不管怎麼樣,這樣也太麻煩了。我們直接傳數組過去讓chars指不就好了嗎?這樣的話主函數就不用再寫什麼指針,老老實實寫個數組再傳就OK了!
int main(){
char shuzu[] = "abcdefg";
scanf("%s",&shuzu);
output(shuzu);
return 0;
}
OK,問題解決!
問題總結
我當時看到這個問題的時候,第一眼看過去好像還真是那麼回事,從上述的代碼分析也可以看出,其實這些代碼要幹什麼我們都懂,但我的那位同學就是遇到了這個‘簡單’的問題。
爲什麼說這個問題是個‘簡單’的問題?還是文章開頭所說:這個問題其實並不難,個人認爲這個問題只要簡單的認識指針到底是什麼?指針到底怎麼用?就可以搞懂這個問題了!
本人水平有限,我認爲寫一些能給大家幫助的文章非常有必要,同時鞏固自己的思想,我認爲邏輯思考能力十分重要,希望一些平時有很多疑惑的朋友務必要有思考的精神!
最後,如果大家覺得本文有幫助,記得支持一下哦!大二菜鳥歡迎交流!