C語言-指針初級(指針定義、指針的作用、指針的計算、野指針、懸空指針、void類型指針)

本章概述思維導圖:

C語言指針

指針是C語言中最強大但也最容易混淆的特性之一。它提供了直接操作內存地址的能力,使得C語言具有高效性和靈活性。下面我將詳細介紹C語言指針的各個方面。

指針定義

指針的本質:指針是一個變量,其值為另一個變量的內存地址;可以理解為:(普通變量:存儲數據值的變量)、(指針變量:存儲內存地址的變量);

指針變量定義格式:

指針查詢數據和修改數據格式:

指針注意事項:

1.數據類型 :要跟指向變量的類型保持一致;

2.定義中的' * ':這是標記,不是解引用的含義;

3.變量名和指針名都是自己起的名字;

4.指針指向變量名時,指向的是內存地址,并不是數據,所以要用取地址符&;

5.定義中的‘ * ’是標記,查詢數據和存儲數據中的‘ * ’是解引用,二者并不一樣;

代碼示例:

#include <stdio.h>
int main()
{int num1=100;int *p=&num1;printf("num1=%d\n",num1);printf("指針指向的內存地址上的值為:%d\n",*p);return 0;
}//代碼運行結果:
num1=100
指針指向的內存地址上的值為:100

代碼講解:首先定義一個整型變量num1并賦值為100,然后聲明一個整型指針p并用&運算符將num1的地址賦給它(此時p存儲的是num1的內存地址),接著通過printf直接輸出num1的值,再通過解引用指針*p(即訪問p指向的內存地址中的值)輸出相同結果,最終證明指針p確實指向了num1的內存空間。

指針使用細節:

1.指針變量的名字不能重復定義;

2.指針變量的數據類型要跟指向變量的類型保持一致;

3.指針變量占用的大小,跟數據類型無關,跟操作系統有關;(32位操作系統:占4個字節,64位操作系統占8個字節);

4.給指針變量賦值時,不能把一個數值賦值給指針變量;

指針的作用

指針的作用1:操作其它函數中的變量

指針的一個重要作用是在不同函數之間直接操作變量,避免全局變量的使用,同時提高代碼的靈活性和效率。

代碼示例(利用指針在不同函數交換變量):

#include <stdio.h>
void huan(int *p1,int *p2);//函數封裝:交換變量
int main()
{int num1=100;int num2=1000;printf("初始值為:num1=%d\tnum2=%d\n",num1,num2);huan(&num1,&num2);printf("交換后值為:num1=%d\tnum2=%d\n",num1,num2);return 0;
}
void huan(int *p1,int *p2)//函數封裝:交換變量
{int temp=0;temp=*p1;*p1=*p2;*p2=temp;
}//代碼運行結果:
初始值為:num1=100	num2=1000
交換后值為:num1=1000	num2=100

代碼講解:在?main?函數中定義兩個變量?num1?和?num2,調用?huan?函數時傳遞它們的地址(&num1?和?&num2),huan?函數通過指針參數(int *p1?和?int *p2)接收地址,并通過解引用(*p1?和?*p2)直接修改原始變量的值,最終完成交換。

關鍵點在于傳遞地址而非值,使得函數能操作外部變量,避免了值傳遞的副本限制,體現了指針在間接訪問和修改數據時的核心作用。


指針的作用2:函數返回多個值

在C語言中,函數通常只能通過返回值傳遞一個結果,但通過指針參數,可以繞過這一限制,實現返回多個值的效果。

代碼示例(在數組中找出最大值和最小值):

#include <stdio.h>
void out_max_min(int arr[],int len,int *p1,int *p2);//函數封裝:找最大值和最小值
int main()
{int arr[]={88,54,69,75,25};int len=sizeof(arr)/sizeof(int);for(int i=0;i<len;i++){printf("%d\t",arr[i]);}putchar('\n');int max=0,min=0;out_max_min(arr,len,&max,&min);printf("數據中最大值為%d\t最小值為:%d\n",max,min);}
void out_max_min(int arr[],int len,int *p1,int *p2)//函數封裝:找最大值和最小值
{*p1=arr[0];*p2=arr[0];for(int i=0;i<len;i++){if(*p1<arr[i])//找最大值{*p1=arr[i];}if(*p2>arr[i])//找最小值{*p2=arr[i];}}
}//代碼運行結果:
88	54	69	75	25	
數據中最大值為88	最小值為:25

代碼講解:在?main()?函數中定義數組并計算長度,打印數組后調用?out_max_min()?函數,傳入數組、長度以及?max?和?min?的地址;該函數先將指針指向的值初始化為數組首元素(避免初始化為?0?導致全負數數組出錯),然后遍歷數組,通過指針更新最大值和最小值,最終返回結果到?main()?函數并打印。


指針的作用3:函數的結果和計算狀態分開

在C語言中,指針的核心價值之一是實現“計算邏輯”與“結果存儲”的分離,使函數能夠專注于核心任務(如數據處理),而將結果的去向交由調用者控制。

代碼示例(定義函數,將兩數相除,獲取他們的余數。返回值為這段算數是否有意義):

#include <stdio.h>
int yu(int *p1,int *p2,int *p3);
int main()
{int num1,num2;int num3=0;printf("輸入兩個數智能獲取余數\n");scanf("%d%d",&num1,&num2);int flag=yu(&num1,&num2,&num3);if(flag){printf("式子無意義");}else{printf("余數為:%d",num3);}return 0;
}
int yu(int *p1,int *p2,int *p3)//函數封裝:將兩數相處,獲取余數。返回值為0這個式子有意義,返回值為1,這個式子無意義
{if(*p2 == 0){return 1;}*p3=*p1%*p2;return 0;
}//代碼運行結果:
輸入兩個數智能獲取余數
85
7
余數為:1

代碼講解:主函數中用戶輸入兩個整數后,將它們的地址連同存儲余數的變量地址一起傳給yu()函數,函數內通過指針參數直接讀取輸入值并檢查除數是否為零,若為零則返回錯誤標志1,否則計算余數并通過指針將結果寫入主函數的變量中,最后主函數根據返回值判斷輸出余數或錯誤提示,這種設計既利用指針高效傳遞了計算結果,又通過返回值清晰區分了正常和異常情況。


指針作用4:方便操作數組和函數傳參

指針操作數組的核心優勢在于它能直接通過內存地址高效訪問和修改元素,避免了數組下標計算的間接開銷,同時支持動態內存分配(如用malloc創建可變大小的數組),且在函數間傳遞數組時只需傳遞首地址指針而非整個數組,極大節省了內存和時間開銷,尤其適合處理大規模數據或多維數組等復雜結構,但需注意指針的邊界控制以防止越界訪問。

代碼示例(在函數中使用指針對數組進行遍歷):

#include <stdio.h>
void arr_bianli(int *p,int *p1);//函數封裝:利用指針對數組遍歷
int main()
{int arr1[]={1,2,3,4,5,6,7,8,9};int len=sizeof(arr1)/sizeof(int);arr_bianli(arr1,&len);return 0;
}
void arr_bianli(int *p,int *p1)//函數封裝:利用指針對數組遍歷
{for(int i=0;i<*p1;i++){printf("arr[%d]=%d\t",i,*(p+i));}putchar('\n');
}//代碼運行結果:
arr[0]=1	arr[1]=2	arr[2]=3	arr[3]=4	arr[4]=5	arr[5]=6	arr[6]=7	arr[7]=8	arr[8]=9	

代碼講解:主函數中定義數組?arr1?并計算其長度?len,調用?arr_bianli()?時傳遞數組首地址(arr1)和長度指針(&len),函數內通過指針解引用獲取長度(*p1)控制循環次數,并利用指針算術(*(p+i))訪問每個元素并打印其下標和值,這種方式避免了數組拷貝,直接操作內存地址,既高效又清晰地展示了指針與數組的緊密關聯。


指針的計算

指針的計算是C語言中操作內存地址的核心機制,它通過基于數據類型大小的地址偏移實現高效的數據訪問和內存操作。

指針的定義:

指針中數據類型的作用:獲取字節數據的個數;

步長:指針移動一次的字節個數

char:1個字節;????????short:2個字節? ? ? ? int:4個字節? ? ? ? longlong:8個字節;

指針加法:指針往后移動了n步,總字節=n*sizeof(數據類型)=N個字節;

指針減法:指針往前移動了n步,總字節=n*sizeof(數據類型)=N個字節;

代碼示例:

#include <stdio.h>
int main()
{//int類型指針步長int arr1[]={1,22,33,44};int *p1=arr1;printf("int類型指針移動2次多少字節:%d字節\narr1[2]=%d\n",2*sizeof(int),*(p1+2));//char類型指針步長char arr2[]="abcd";char *p2=arr2;printf("char類型指針移動2次多少字節:%d字節\narr2[2]=%c\n",2*sizeof(char),*(p2+2));return 0;
}//代碼運行結果:
int類型指針移動2次多少字節:8字節
arr1[2]=33
char類型指針移動2次多少字節:2字節
arr2[2]=c

代碼講解:指針的加減運算會根據其指向的數據類型自動計算地址偏移量:當對指針進行?+n?或?-n?操作時,實際移動的字節數等于?n × sizeof(數據類型)(例如?int*?每次移動4字節,char*?每次移動1字節),因此?*(p + i)?能直接訪問數組第i個元素(如?int* p?指向數組時,p+2?會跳過8字節訪問?arr[2]),這種機制使得指針運算與數組索引天然對應,但需注意避免越界訪問。

指針步長和指針變量占用大小的區別

指針步長和指針變量占用大小是兩個完全不同的概念,前者決定指針移動時的地址偏移量,后者反映指針變量本身在內存中占用的空間。

指針步長:由指針指向的數據類型決定,計算公式為:步長 =?sizeof(數據類型);

指針變量占用大小:指針變量本身在內存中占用的字節數。由操作系統和編譯器決定(與指針類型無關),通常為:32位系統:4字節、64位系統:8字節;

C語言野指針

野指針(Wild Pointer)是指未初始化或已釋放的指針變量,其指向的內存地址不可預測或無效。訪問野指針會導致未定義行為(如程序崩潰、數據損壞)。

野指針的常見成因

1.未初始化的指針

代碼示例:

#include <stdio.h>
int main()
{int *p;*p=10;printf("%d\n",*p);return 0;
}//代碼運行結果:
段錯誤 (核心已轉儲)

代碼講解:未初始化,p的值是隨機地址(野指針),危險!可能訪問非法內存;


2. 指針越界訪問

代碼示例:

#include <stdio.h>
int main()
{int arr[3]={1,2,3};int *p=arr;p+=5;printf("%d\n",*p);return 0;
}//代碼運行結果:
-912009440

C語言野指針總結

野指針的本質:指向不可控或無效內存的指針。

防范手段:

1. 初始化指針為?NULL

2. 釋放內存后立即置空。

3. 確保指針操作在合法范圍內。

C語言懸空指針

懸空指針是指指向已被釋放或回收的內存地址的指針。此時指針仍保存著舊的內存地址,但該地址已無效,訪問它會導致未定義行為(如程序崩潰或數據損壞)。

懸空指針的常見成因

1.內存被釋放后未置空

代碼示例:

#include <stdio.h>
#include <stdlib.h>
int main()
{int *p=malloc(sizeof(int));*p=10;free(p);*p=20;printf("%d\n",*p);return 0;
}//代碼運行結果:
段錯誤

代碼講解:free已經釋放內存了,此時p仍指向原地址,成為懸空指針,危險!訪問已釋放的內存


2.局部變量指針超出作用域

代碼示例:

#include <stdio.h>
int *num(void);//函數封裝:返回數據
int main()
{int *p=*num();printf("%d",*p);return 0;
}
int *num(void)//函數封裝:返回數據
{int num1=10;return &num1;
}//代碼運行結果:
段錯誤 (核心已轉儲)

代碼講解:函數num返回局部變量num1的地址,可是num1在函數結束后被銷毀釋放了。因此成為懸空指針,在主函數中*p是屬于未定義行為;

C語言懸空指針總結

懸空指針的本質:指針與內存生命周期不同步。

防范手段:

1.釋放內存后立即置空(p = NULL)。

2.不返回局部變量的地址。

3.使用動態內存分配(malloc)替代局部變量。


void類型的指針

void*(無類型指針)是一種通用指針類型,可以指向任意數據類型(如?intfloat、結構體等),但不能直接解引用(即不能通過?*?訪問值),必須先轉換為具體類型的指針。

代碼示例:

#include <stdio.h>
int main()
{int num1=10;void *p=&num1;int *p1=(int*)p;printf("%d\n",*p1);return 0;
}//代碼運行結果:
10

代碼講解:先定義一個整型變量?num1?并賦值為 10,再用?void* p?存儲其地址(此時?p?僅保存地址信息,不關聯具體類型),接著通過顯式類型轉換?(int*)p?將?void*?還原為?int*?指針?p1,最后通過?p1?解引用并打印?num1?的值(10),體現了?void*?作為通用指針需轉換后才能操作數據的特性,同時強調了類型轉換必須與實際數據類型匹配,否則會導致未定義行為。


制作不易!喜歡的小伙伴給個小贊贊!喜歡我的小伙伴點個關注!有不懂的地方和需要的資源隨時問我喲!

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

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

相關文章

具身智能VLA困于“數據泥潭”,人類活動視頻數據是否是“破局之鑰”?

前言盡管當前的視覺-語言-動作&#xff08;VLA&#xff09;模型已展現出顯著進展&#xff0c;但其在新場景和與復雜物體交互中的性能會顯著下降&#xff0c;在遵循指令方面落后于像LLaVA 這樣的大型多模態模型&#xff08;LMM&#xff09;。這種局限性源于現有VLA模型對存在固有…

CIO如何規劃企業BI分析指標體系 —— 從經營出發到績效管理

如果你是一家企業的CIO&#xff0c;要啟動一個商業智能BI項目&#xff0c;負責規劃整個項目的商業智能BI分析內容&#xff0c;你該如何入手準備&#xff1f;要有什么樣的思路。如果是管理層、老板還不能清晰認識到商業智能BI的價值&#xff0c;也提不出很清晰的需求&#xff0c…

go學習筆記:panic是什么含義

anic 是 Go 語言中的一種運行時錯誤處理機制&#xff0c;用于處理程序中的異常情況。 基本含義 panic 會&#xff1a; 立即停止當前函數的執行 開始執行 defer 函數&#xff08;如果有的話&#xff09; 向上傳播到調用棧&#xff0c;逐層執行 defer 如果到達 main 函數&am…

OpenLayers 入門指南【五】:Map 容器

文章目錄 一、Map 對象核心參數 1. target 2. view 3. layers 4. controls 5. interactions 6. 其他重要參數 二、Map 對象常用方法 1. 圖層管理 2. 控件管理 3. 交互管理 4. 視圖與坐標操作 5. 事件監聽 6. 覆蓋物管理 7. 其他 三、總結 上一章節中我們通過修改OlMap.vue組件已…

關稅戰火中的技術方舟:新西蘭證券交易所的破局之道 ——從15%關稅沖擊到跨塔斯曼結算聯盟,解碼下一代交易基礎設施

一、今日焦點&#xff1a;全球關稅震蕩與新西蘭的“技術自衛” 1. 特朗普關稅大限落地&#xff0c;新西蘭啟動緊急游說 2025年8月1日&#xff0c;美國總統特朗普正式簽署行政令&#xff0c;對貿易順差國征收最低15%基準關稅。新西蘭貿易部長緊急聲明&#xff1a;“將提出有力證…

windows內核研究(軟件調試-軟件斷點)

軟件調試軟件斷點調試的本質是什么&#xff1f;就是在被調試程序中觸發異常&#xff0c;然后被調試程序就會向_DEBUG_OBJECT結構體添加調試事件&#xff0c;這里我們調試器就接管這個異常了&#xff08;調試的過程就是異常處理的過程&#xff09; 軟件斷點 在x64dbg中通過快捷鍵…

HarmonyOS】鴻蒙應用開發中常用的三方庫介紹和使用示例

&#x1f31f; 鴻蒙應用開發常用三方庫指南&#xff08;2025 最新版&#xff09;適用版本&#xff1a;HarmonyOS NEXT / API 12 參考來源&#xff1a;HarmonyOS 三方庫中心 截止至 2025 年 8 月 1 日&#xff0c;本文整理了當前社區中下載量高、穩定性強、生態完善的熱門三方庫…

【通識】C Sharp

1. 使用 \p{名稱}構造匹配Unicode常規類別&#xff08;該示例為Pd或“標點、短劃線”類別&#xff09;和命名塊&#xff08;IsGreek和IsBsicLatin命名塊&#xff09; using System; using system.Text.RegularExpressions; public class Example {public static void main() {s…

國內首個開源SCA社區——OpenSCA開源社區

OpenSCA開源社區成果說明項目背景智能時代&#xff0c;軟件定義一切。隨著開發模式的敏捷化轉型&#xff0c;開源代碼在軟件制品中的占比越來越大&#xff0c;開源軟件已然成為軟件供應鏈的重要組成部分。由于其特殊性&#xff0c;開源代碼的引入增加了軟件應用的風險面&#x…

超聚變:智能體時代,AI原生重構城企數智化基因

2025 世界人工智能大會&#xff08;WAIC&#xff09;世博展覽館內&#xff0c;超聚變展臺前人頭攢動&#xff0c;其展示的AI落地全棧解決方案及上百個AI應用場景吸引了眾多參觀者駐足觀看。這是今年WAIC大會火爆的一角&#xff0c;更是當下AI應用爆發的一個縮影。當人工智能發展…

Traccar:開源GPS追蹤系統的核心價值與技術全景

Traccar&#xff1a;開源GPS追蹤系統的核心價值與技術全景 —— 從設備兼容到企業級定位管理的開源實踐 一、項目定位&#xff1a;多場景定位管理的開源基石 Traccar是一個高擴展性的開源GPS追蹤平臺&#xff0c;支持全球超過200種通信協議與2000款GPS設備&#xff08;包括車…

編程與數學 03-002 計算機網絡 20_計算機網絡課程實驗與實踐

編程與數學 03-002 計算機網絡 20_計算機網絡課程實驗與實踐一、實驗環境搭建&#xff08;一&#xff09;使用模擬器&#xff08;如Cisco Packet Tracer&#xff09;搭建網絡實驗環境&#xff08;二&#xff09;實驗設備的配置與連接二、基礎網絡實驗&#xff08;一&#xff09…

15個命令上手Linux!

1、id&#xff0c;顯示當前登錄系統的用戶信息2、pwd&#xff0c;顯示當前工作目錄的絕對路徑3、ls&#xff0c;顯示當前目錄下的內容&#xff08;ls -r&#xff1a;按反向順序列出內容&#xff0c;ls -l&#xff1a;以詳細列表形式顯示&#xff09;4、cd&#xff0c;切換工作目…

MongoDB分片技術實現

MongoDB分片技術實現概述MongoDB分片&#xff08;Sharding&#xff09;是MongoDB的水平擴展解決方案&#xff0c;通過將數據分布到多個分片&#xff08;shard&#xff09;上來處理大數據量和高吞吐量的需求。MongoDB分片架構1. 分片集群組件# MongoDB分片集群架構 version: 3.8…

Python開發環境PyCharm下載與安裝

python下載 python下載地址&#xff1a; Download Python | Python.org 上面的下載速度慢的話&#xff0c;用下面的地址下載&#xff08;window&#xff09;&#xff1a; https://download.csdn.net/download/liangmengbk/91580033 PyCharm下載 PyCharm下載地址&#xff1a…

汽車供應鏈PPAP自動化審核指南:如何用AI實現規則精準匹配與文件智能校驗

在汽車行業質量管理的核心環節&#xff0c;PPAP&#xff08;生產件批準程序&#xff09;審核長期困擾著供應商與主機廠。 隨著IATF 16949等標準持續升級、新能源零件復雜度激增&#xff0c;傳統人工審核模式正面臨系統性挑戰。 行業數據顯示&#xff0c;超過70%的SQE&#xf…

正則表達式在js中的應用

正則表達式在 JavaScript 中的應用非常廣泛&#xff0c;尤其是在字符串處理和驗證方面。以下是一些常見的正則表達式方法及其應用示例&#xff0c;包括 .test() 方法。 1. .test() 方法 .test() 方法用于測試一個字符串是否匹配正則表達式。如果匹配&#xff0c;返回 true&…

Rust視頻處理開源項目精選

Rust視頻處理開源項目精選 基于Rust實現的視頻處理示例 以下是一些基于Rust實現的視頻處理或多媒體相關的開源項目或示例,涵蓋編解碼、流媒體、分析工具等方向,可作為實際開發參考: 視頻編解碼與處理 rav1e:Rust編寫的AV1視頻編碼器,高性能且內存安全,適合研究視頻壓縮…

Python爬蟲實戰:研究pycrumbs庫,構建豆瓣讀書數據采集系統

1. 引言 1.1 研究背景 在大數據與人工智能技術快速發展的背景下,互聯網作為全球最大的信息載體,蘊含著海量結構化與非結構化數據。高效、合規地獲取這些數據成為數據分析、業務決策的前提。網絡爬蟲作為自動化數據采集工具,通過模擬人類瀏覽行為遍歷網頁并提取信息,已成為…

linux的用戶操作(詳細介紹)

在 Linux 系統中&#xff0c;用戶管理是系統管理員的核心工作之一&#xff0c;涉及用戶賬號的創建、修改、刪除、權限分配等操作。Linux 采用多用戶多任務機制&#xff0c;通過嚴格的用戶和組管理確保系統安全性和資源分配合理性。以下是 Linux 用戶操作的詳細介紹&#xff1a;…