指針在c語言中的運用,怎么理解C語言中的指針,如何運用?

恰好我之前寫了一系列介紹 C 語言的文章,介紹了什么是指針,以及為什么要使用指針,下面摘錄一部分,感興趣的話,可以點我了解更多。

什么是 C語言指針?

不同的數據類型的主要區別在于占用的存儲空間不同。我們知道,C 程序是運行在計算機的內存中的,因此 C 程序的變量也是存在于內存中的。C 標準規定 char 類型占用一個字節的存儲空間,對其他整型卻沒有做規定,現在為了解釋的方便,我們假設 int 類型的數據占用內存 4 個字節。

假設我們如下定義了兩個變量:signed char i = 3;int j = 8;

那么,i 占用了 1 字節的內存空間,j 占用了 4 字節的內存空間,請看下圖。

方框表示內存空間,內部表示存儲的值。我們把內存逐字節編號,方框外部的數字表示方框的編號(這樣的內存“編號”即所謂的“內存地址”)。修改變量 i 的值,實際上就是修改地址為 4000 的內存空間里的值。那反過來呢?如果我修改了地址為 4000 的內存空間里的值,i 的值會相應改變嗎?答案是肯定的,請繼續往下看。

上圖中的內存地址“4000”是我為了解釋方便隨意取的。那么,在實際應用中,變量 i 的地址如何獲取呢?C 語言提供了“&”運算符,就是獲取變量地址的。請看下面的例子:#include int main()

{

signed char i = 3;

int j = 8;

long p1 = (long)&i;

printf('p1: %ld ', p1);

return 0;

}

我們取出了 i 的地址,把它強制轉換為 long 型(關于強制類型轉換,可參考上一節),傳遞給 p1 了。編譯執行,發現變量 i 的地址被打印出來了。這說明,C 程序變量的地址也是一個整數。

按照上面的說法,修改 i 的值除了直接對 i 賦值以外,還可以通過修改 p1 地址處的內存空間里的數值。那,怎樣才能“通過修改 p1 地址處的內存空間里的數值”修改 i 的值呢?

上面的代碼實例中,我們使用了 long 型變量 p1 存儲了 i 的地址。事實上,C 語言有專門的數據類型存儲地址,定義方式也很簡單,就是:“類型描述符 * ”,例如,可以定義以下變量存儲地址:signed char *p1 = &i;int *p2 = &j;

p1 和 p2 就是 C 語言中所謂的指針類型,因為 i 是 signed char 類型的,所以定義了 signed char * 類型的指針存儲 i 的地址。j 是 int 類型的,所以定義了 int * 類型的指針存儲 j 的地址。另外,C 語言提供了“&”運算符取變量地址,與之對應的,還提供了“ * ”運算符從相應地址內存里取出數值。

好了,了解了 C 語言的指針類型和“ * ”運算符,現在來看看如何“通過修改 p1 地址處的內存空間里的數值”修改 i 的值。請看如下代碼:signed char *p1 = &i;

*p1 = 5;

printf('i=%d ', i);

編譯運行,發現程序輸出“i=5”,這樣我們就實現了“通過修改 p1 地址處的內存空間里的數值”修改 i 的值。在定義變量時,” * “放在變量符號前,可以定義指針變量。在定義完指針變量后,“ * ”放在變量前,就表示從地址取值的運算符了。另外,“ * ”還可以表示乘法運算符,讀者自己思考什么情況下,“ * ”表示乘法運算符。

以上的操作,實際上就是 C 語言的指針操作,可以看出它一點也不神秘,接下來幾節,我們將繼續討論 C 語言的指針,比如為什么 int 類型的變量 j 的地址要使用 int* p2; 定義,而不能使用 signed char* p2; 定義,使用指針為何能寫出緊湊、高效的 C 程序等等。

為什么要使用指針?

在開始討論為什么使用 C 語言指針之前,先介紹一下復雜點的指針,這是新知識,也是鋪墊。不想看鋪墊可以往后翻一翻。

前面幾節介紹了 C 語言中指針,也討論了數組指針和指針數組的區別,但歸根結底,至今我們說的都是基礎數據類型定義的指針,C 語言有復合數據類型,那么它有復合數據類型的指針嗎?答案是肯定的,事實上,在 C 語言中復合類型指針的使用相當廣泛。

先來看看結構體指針。還是從實例出發,我們定義一個結構體類型,它有兩個成員,分別是 sleep_time(睡覺時間) 和 work_time(工作時間),然后定義這種結構體類型的變量和指針:struct week{

double sleep_time;

double work_time;

};

struct week w;

struct week *pw = &w;

可以通過結構體指針 pw 訪問 week 結構體的成員:(*pw).sleep_time = 7.0;

這樣寫有點麻煩,因此 C 語言非常貼心的提供了“->”運算符,所以我們還可以這樣通過結構體指針訪問成員:pw->sleep_time = 7.0;

為什么要使用 C 語言中的指針

好了,現在我們已經知道 C 語言中的結構體指針怎么使用了,鋪墊完了。但是,明明使用結構體變量 w 就能很好的讀寫 week 結構體啊,為什么要用結構體指針呢?這不是麻煩了嗎?為什么要使用結構體指針,其實可以延伸到“為什么要使用指針”,本節將以結構體指針為例討論一下這個問題。

是的,僅僅訪問 week 的 sleep_time 成員,只使用結構體變量 w 就足夠了,再通過 pw 訪問真的麻煩了。但是工具會不會帶來方便,要看我們怎么使用,不能因為高射炮打蚊子不方便就說高射炮沒用。恰當的使用結構體指針,有利于我們寫出更加緊湊,效率更高的 C 程序。

一周有五天工作日,兩天周末,一般來說,在工作日(weekday),人們的睡覺時間較短,工作時間較長,所以我們定義 weekday 函數來規劃工作日的時間:void weekday(struct week wd)

{

wd.sleep_time = 7.0; // 7 小時

wd.work_time = 8.5; // 8.5 小時

}

而在周末(weekend)則反過來,工作間較短,睡覺時間較長,所以我們定義 weekend 函數來規劃周末的時間:void weekend(struct week we)

{

we.sleep_time = 9.0; // 9 小時

we.work_time = 2.5; // 2.5 小時

}

這兩個函數很好的規劃了一周的睡覺和工作時間,但是卻并不好用。為什么呢?因為它倆只在自己內部規劃了,我們外界看不到啊!想在 main 函數把規劃好的時間打印出來都辦不到,因為它倆在自己內部規劃好以后,就把“規劃書”銷毀了。這里把 weekday 和 weekend 函數的局部變量比作“規劃書”,函數退出后,局部變量就自動銷毀了。可以參考《c語言入門5,一文徹底弄懂函數的形參和實參》一節。

可能你會說,那我可以把“規劃書”返回給 main 函數啊,讓 weekday 和 weekend 函數有返回值就可以了:struct week weekday(struct week wd)

{

wd.sleep_time = 7.0; // 7 小時

wd.work_time = 8.5; // 8.5 小時

return wd;

}

struct week weekend(struct week we)

{

we.sleep_time = 9.0; // 9 小時

we.work_time = 2.5; // 2.5 小時

return we;

}

int main()

{

struct week w;

w = weekday(w);

printf('weekday, sleep time: %0.1f, work time: %0.1f ', w.sleep_time, w.work_time);

weekend(w);

printf('weekend, sleep time: %0.1f, work time: %0.1f ', w.sleep_time, w.work_time);

return 0;

}

是的,這的確是一個解決問題的辦法,main 可以把 weekday 和 weekend 函數的“規劃書”打印出來了。

但是這種解決問題的辦法有一點臃腫,很多程序員把這樣的代碼稱為“不優雅”的代碼。你看,main 現在有一份空的“規劃書”,需要 weekday 和 weekend 函數處理。weekday 和 weekend 函數能處理,但是它們要復制一份“規劃書”回到自己內部做,這種復制就造成了空間浪費。此外,weekday 和 weekend 函數做完了規劃書,還要把“規劃書”再從自己內部取出,return 給 main,這就有時間浪費。

更節約資源,更有效率的做法是:weekday 和 weekend 函數處理這份“規劃書”時,直接處理 main 里的“規劃書”就可以了。不要復制后再處理,完事了還要在從自己內部傳出。那,weekday 和 weekend 函數應該怎么修改呢?請看:void weekday(struct week *wd)

{

wd->sleep_time = 7.0; // 7 小時

wd->work_time = 8.5; // 8.5 小時

}

void weekend(struct week *we)

{ we->sleep_time = 9.0; // 9 小時

we->work_time = 2.5; // 2.5 小時

}

int main()

{

struct week w;

weekday(&w);

printf('weekday, sleep time: %0.1f, work time: %0.1f ', w.sleep_time, w.work_time);

weekend(&w);

printf('weekend, sleep time: %0.1f, work time: %0.1f ', w.sleep_time, w.work_time);

return 0;

}

看到了沒,利用指針,整個 C 代碼簡潔多了。weekday 和 weekend 函數接收到的參數都是 main 里結構體變量 w 的地址,所以它倆都是直接操作 w 的。這樣就不用在自己的棧幀里復制一份 w 再處理了,也不用在處理完畢還要 return 給 main 了。

看到這里,你可能會說,什么嘛,不就是用指針代替了結構體做參數嗎?指針說不定比結構體還要耗空間呢!對嗎?一起來看下:結構體變量 w,它占用內存至少兩個 sizeof(double) 的空間(一個 double 型數據通常占用 8 字節空間)。而一個指針,不管它是什么類型的,在大多數 32 位計算機中,它只占 4 字節空間,在大多數 64 位計算機中,它也僅僅占 8 字節空間。所以使用指針做 weekday 和 weekend 函數的參數,在空間上,絕對是比直接使用 week 結構體節約空間的,何況指針還提升了效率,簡潔了代碼。如果是一個 char 型變量,它只占用 1 字節空間,這時使用指針的確更浪費空間。但是如果是一個非常復雜的結構體,它占用的內存空間甚至達幾千字節,這時使用指針就非常節約空間了。所以說,工具是死的,人是活的。

到這里,相信你已經了解 C 語言指針在節約空間,提升程序效率方面的作用了。事實上,這里我們介紹的僅僅是指針的冰山一角,在以后的文章里,你會愈發覺得 C 語言指針的強大的。

歡迎在評論區一起討論,質疑。文章都是手打原創,每天最淺顯的介紹C語言,喜歡我的文章就關注一波吧,可以看到最新更新和之前的文章哦。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/541695.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/541695.shtml
英文地址,請注明出處:http://en.pswp.cn/news/541695.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

設計模式(一)單例模式的七種寫法

1. 餓漢模式 public class Singleton { private static Singleton instance new Singleton(); private Singleton (){}public static Singleton getInstance() { return instance; } } View Code這種方式在類加載時就完成了初始化,所以類加載較慢,…

scala 字符串轉換數組_如何在Scala中將字節數組轉換為字符串?

scala 字符串轉換數組Byte Array in Scala is an array of elements of a byte type. String in Scala is a collection of the character data type. Scala中的字節數組是字節類型的元素的數組。 Scala中的String是字符數據類型的集合。 將字節數組轉換為字符串 (Convert byt…

智能關機軟件 c語言,智能關機軟件

智能關機軟件是一款免費共享關機軟件。智能關機軟件不但具有定時關機、自動關機的功能,而且還可以進行定時提醒信息、打開文件、打開網頁、重啟計算機、注銷用戶、鎖定計算機、計算機休眠、計算機待機、關閉顯示器,并且可以進行多任務計劃,可…

wget: command not found

-bash: wget: command not found的兩種解決方法 今天給服務器安裝新LNMP環境時,wget 時提示 -bash:wget command not found,很明顯沒有安裝wget軟件包。一般linux最小化安裝時,wget不會默認被安裝。可以通過以下兩種方法來安裝:1、rpm 安裝rp…

數據庫數據規范化看不懂_數據庫管理系統中的規范化

數據庫數據規范化看不懂DBMS中的規范化 (Normalization in DBMS) Every table must have a single idea. The method by which we divide tables approximately is called normalization and the rest used for normalization is a functional dependency. For the normalizati…

c 語言開發一個四則運算器,C++實現四則運算器(無括號)

本文實例為大家分享了C實現無括號的四則運算器的具體代碼,供大家參考,具體內容如下完成度更高的帶括號版本可以看C實現四則運算器(帶括號)對于無括號的計算器,實現起來比較容易,下面讓我們一步步實現。舉例首先明確需要實現怎樣的…

iOS開發之解決系統數字鍵盤無文字時delete鍵無法監聽的技巧

最近在做用戶登錄獲取驗證碼時添加圖形驗證碼功能,就是只有正確輸入圖形驗證碼才能收到后臺發送的短信驗證碼。效果如下: 看起來雖然是個小功能,但是實際操作起來,會發現蘋果給我們留下的坑,當然更多的是自己給自己挖的…

c ++查找字符串_C ++結構| 查找輸出程序| 套裝1

c 查找字符串Program 1: 程序1&#xff1a; #include <iostream>#include <math.h>using namespace std;struct st {int A NULL;int B abs(EOF EOF);} S;int main(){cout << S.A << " " << S.B;return 0;}Output: 輸出&#xff1a…

二級c語言加油,二級C語言 備考指南及常見問題(2013版)

該樓層疑似違規已被系統折疊 隱藏此樓查看此樓3、關于上機操作部分的復習最好買一本上機題庫方面的教材&#xff0c;或打印、閱讀南開百題之類的電子文檔。配合上機模擬軟件(無紙化考試軟件)&#xff0c;上機練習是必須的。上機軟件一般有100套題多一點&#xff0c;每套有程序填…

開放定址散列表

再散列之后散列函數要重新計算。 // kaifangliaobiao.cpp : 定義控制臺應用程序的入口點。 //使用平方探測解決沖突問題時&#xff0c;散列表至少空一半時&#xff0c;總能插入一個新的元素#include "stdafx.h" #include<iostream> using namespace std;#ifnde…

合并兩個鏈表數據結構c語言,合并兩個鏈表.

該樓層疑似違規已被系統折疊 隱藏此樓查看此樓#include #define N1 10#define N2 10struct list{int date ;struct list *next;};main(){struct list *p1,*p2,*p3,*p4,*head,*head1,*head2,*p;int n0;head1head2NULL;p1p2(struct list *)malloc(sizeof(struct list));p1->da…

c ++查找字符串_C ++結構| 查找輸出程序| 套裝2

c 查找字符串Program 1: 程序1&#xff1a; #include <iostream>using namespace std;int main(){typedef struct{int A;char* STR;} S;S ob { 10, "india" };S* ptr;ptr &ob;cout << ptr->A << " " << ptr->STR[2];…

連接fiddler后手機無法顯示無網絡

升級了fiddler到4.6版本&#xff0c;手機設置代理后提示無網絡&#xff0c;試試以下解決方法&#xff1a; 1.fiddler升級后對應的.net framework也要升級&#xff0c;安裝最新的.net framework 4.6&#xff0c;升級安裝后&#xff0c;可以正確抓包啦 2.如果上述方法無效&#x…

android 人臉解鎖 鎖屏動畫,人臉保護鎖(人臉識別鎖屏)

這是一款十分炫酷的鎖屏工具&#xff0c;還記得電影中的特工所用的人臉識別鎖嗎&#xff1f;這款應用也能讓你過過癮&#xff01;人臉識別鎖屏安卓版是一款用人臉做密碼來打開手機屏保鎖的一個APP。不僅可以作屏保鎖&#xff0c;也可以單獨保護某些重要程序不被偷窺,例如查看短…

dbms_排名前50位的DBMS面試問答

dbms1) What are the drawbacks of the file system which is overcome on the database management system? 1)在數據庫管理系統上克服的文件系統有哪些缺點&#xff1f; Ans: Data redundancy & isolation, difficulty in accessing data, data isolation, and integri…

linux時間

CST代表中國標準時間rtc實時時鐘linux主要有兩種時間硬件時鐘 clock系統時鐘 date修改時間 date 03300924必須是兩位或者 date -s 2017:03:30將系統時間同步到硬件時間 hwclock -w將硬件時間同步到系統時間 hwclock -s轉載于:https://blog.51cto.com/12372297/1911608

查找Python中給定字符串的所有排列

Python itertools Module Python itertools模塊 "itertools" are an inbuilt module in Python which is a collection of tools for handling iterators. It is the most useful module of Python. Here, a string is provided by the user and we have to print a…

android 圖片疊加xml,Android實現圖片疊加效果的兩種方法

本文實例講述了Android實現圖片疊加效果的兩種方法。&#xff0c;具體如下&#xff1a;效果圖&#xff1a;第一種&#xff1a;第二種&#xff1a;第一種是通過canvas畫出來的效果:public void first(View v) {// 防止出現Immutable bitmap passed to Canvas constructor錯誤Bit…

Win10系列:VC++ 定時器

計時器機制俗稱"心跳"&#xff0c;表示以特定的頻率持續觸發特定事件和執行特定程序的機制。在開發Windows應用商店應用的過程中&#xff0c;可以使用定義在Windows::UI::Xaml命名空間中的DispatcherTimer類來創建計時器。DispatcherTimer類包含了如下的成員&#xf…

dbms系統 rdbms_DBMS與傳統文件系統之間的區別

dbms系統 rdbmsIntroduction 介紹 DBMS and Traditional file system have some advantages, disadvantages, applications, functions, features, components and uses. So, in this article, we will discuss these differences, advantages, disadvantages and many other …