C語言【指針二】

引言

? ? ? ? 介紹:const修飾指針,野指針

? ? ? ? 應用:指針的使用(strlen的模擬實現),傳值調用和傳指調用

一、const修飾指針

1.const修飾變量

????????簡單回顧一下前面學過的const修飾變量:在變量前面加上const,那么這個變量就變成了常量,下面就不能再對這個變量進行修改了,否則就會爆錯。

來看代碼:

#include<stdio.h>const int n = 10;int main()
{printf("n = %d\n",n);return 0;
}

如果想對n重新賦值,就會報錯。

錯誤案例:(編譯器不允許)

但是如果我們繞過n,使用 n 的地址,去修改 n 就能做到了,雖然這樣做是在打破語法規則。?

來看代碼:

#include<stdio.h>
int main()
{const int n = 10;printf("n = %d\n",n);int* p = &n;*p = 20;printf("n = %d\n", n);return 0;
}

運行結果:

?下面來學習const修飾指針,來解決這個問題。

2.const修飾指針變量

const修飾指針變量,可以放在 * 的左邊,也可以放在 * 的右邊,意義是不一樣的。

	int* p; //正常指針,沒有被修飾int const* p;  //const 放在*的左邊來修飾int* const p; // const 放在*的右邊來修飾

const放在*左邊:

    #include<stdio.h>int main(){const int n = 10;printf("n = %d\n",n);int const * p = &n;*p = 20;printf("n = %d\n", n);return 0;}

將 *p給修飾了,下面改*p的內容,編譯器是不允許的。

const放在*右邊:

#include<stdio.h>
int main()
{const int n = 10;int m = 20;printf("n = %d\n", n);int *const p = &n;*p = 20;printf("n = %d\n", n);return 0;
}

?運行結果:
*p是可以被修改了,但是指針變量p就不能被修改了:

#include<stdio.h>
int main()
{const int n = 10;int m = 20;printf("n = %d\n", n);int *const p = &n;*p = 20;printf("n = %d\n", n);p = &m;return 0;
}



const放在*的右邊,將p給修飾了,不能對p的內容(即p指向的地址)修改了。

二、野指針

概念:野指針就是指針指向的位置是不可知的(隨機的、不正確的、沒有明確限制的)

成因:

1. 指針未初始化

#include <stdio.h>
int main()
{int* p;//局部變量指針未初始化,默認為隨機值*p = 20;return 0;
}

指針p指向的地址是隨機的

2. 指針越界訪問

#include <stdio.h>
int main()
{int arr[10] = { 0 };int* p = &arr[0];int i = 0;for (i = 0; i <= 11; i++){//當指針指向的范圍超出數組arr的范圍時,p就是野指針*(p++) = i;}return 0;
}

3.指針指向的空間釋放

#include <stdio.h>
int* test()
{int n = 100;return &n;
}
int main()
{int* p = test();printf("%d\n", *p);return 0;
}

出test()函數的時候,n在內存中的就銷毀了,這時,p指向的地址就是隨機的了

。。。。。。

避免野指針:?

????????如果明確知道指針指向哪里就直接賦值地址,如果不知道指針應該指向哪里,可以給指針賦值NULL,?NULL 是C語言中定義的一個標識符常量,值是0,0也是地址,這個地址是無法使用的,讀寫該地址會報錯。

1.指針初始化?

#include <stdio.h>
int main()
{int num = 10;int* p1 = &num;int* p2 = NULL;return 0;
}

2.小心指針越界

? ? ? ? 一個程序向內存申請了哪些空間,通過指針也就只能訪問哪些空間,不能超出范圍訪問,超出了就是越界訪問。(寫代碼的時候,自己注意一點,有時候自己都發現不了)

3.指針變量不再使用時,及時置NULL,指針使用之前檢查有效性?

????????當指針變量指向一塊區域的時候,我們可以通過指針訪問該區域,后期不再使用這個指針訪問空間的時候,我們可以把該指針置為NULL。因為約定俗成的?個規則就是:只要是NULL指針就不去訪問,同時使用指針之前可以判斷指針是否為NULL。

????????我們可以把野指針想象成野狗,野狗放任不管是非常危險的,所以我們可以找?棵樹把野狗拴起來,就相對安全了,給指針變量及時賦值為NULL,其實就類似把野狗栓起來,就是把野指針暫時管理起來。

????????不過野狗即使拴起來我們也要繞著走,不能去挑逗野狗,有點危險;對于指針也是,在使用之前,我 們也要判斷是否為NULL,看看是不是被拴起來起來的野狗,如果是不能直接使用,如果不是我們再去使用。

int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int* p = &arr[0];int i = 0;for (i = 0; i < 10; i++){*(p++) = i;}//此時p已經越界了,可以把p置為NULLp = NULL;//下次使?的時候,判斷p不為NULL的時候再使?//...p = &arr[0];//重新讓p獲得地址if (p != NULL) //判斷{//...}return 0;
}

4.避免返回局部變量的地址

三、指針的使用(strlen的模擬實現)

????????庫函數strlen的功能是求字符串長度,統計的是字符串中函數原型如下:

size_t strlen ( const char * str );

?????????參數str接收?個字符串的起始地址,然后開始統計字符串中 \0 之前的字符個數,最終返回?度。 如果要模擬實現只要從起始地址開始向后逐個字符的遍歷,只要不是 到 \0 就停?。

#include<assert.h>
int my_strlen(const char* str)
{int count = 0; //用于統計字符串的長度assert(str);while (*str){count++;str++; //指針向后走}return count;
}
int main()
{int len = my_strlen("abcdef"); printf("%d\n", len);
}

實現方式不止這一種,還可以最后一個地址的位置減去第一個地址的位置,等等。?

?四、傳值調用和傳址調用

下面通過一個案例來理解一下,什么是傳值調用,什么是傳址調用?

?寫一個交換兩個值的代碼:

#include <stdio.h>
void Swap1(int x, int y)
{int tmp = x;x = y;y = tmp;
}
int main()
{int a = 0;int b = 0;scanf("%d %d", &a, &b);printf("交換前:a = % d b = % d\n", a, b);Swap1(a, b);printf("交換后:a = % d b = % d\n", a, b);return 0;
}

這段代碼,表面一看,沒啥問題,其實是不對的。運行結果:

為什么呢??

解釋:這里的swap1函數在傳參的時候,是把a,b的值賦值給了x和y,x和y有自己的地址,和a,b的地址沒關系,當x和y的值完成交換后,只是x和y的值交換了,a,b地址對應值沒有改變,所以不能完成a,b的交換。

Swap1函數在使用的時候,是把變量本身直接傳遞給了函數,這種調用函數的方式叫傳值調用。

結論:實參傳遞給形參的時候,形參會單獨創建一份臨時空間來接收實參,對形參的修改不影響實 參。?

怎么解決:

????????在main函數中將a和b的地址傳遞給Swap函數,Swap 函數里邊通過地址間接的操作main函數中的a和b,并達到交換的效果就好了。

#include <stdio.h>
void Swap2(int* px, int* py)
{int tmp = 0;tmp = *px;*px = *py;*py = tmp;
}
int main()
{int a = 0;int b = 0;scanf("%d %d", &a, &b);printf("交換前:a = %d b = %d\n", a, b);Swap2(&a, &b);printf("交換后:a = %d b = %d\n", a, b);return 0;
}

運行結果:

????????這?調?Swap2函數的時候是將變量的地址傳 遞給了函數,這種函數調用方式叫:傳址調?。?

????????傳址調用,可以讓函數和主調函數之間建立真正的聯系,在函數內部可以修改主調函數中的變量;所以未來函數中只是需要主調函數中的變量值來實現計算,就可以采用傳值調用。如果函數內部要修改主調函數中的變量的值,就需要傳址調用。

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

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

相關文章

學習記錄-軟件測試基礎

一、軟件測試分類 1.按階段&#xff1a;單元測試&#xff08;一般開發自測&#xff09;、集成測試、系統測試、驗收測試 2.按代碼可見度測試&#xff1a;黑盒測試、灰盒測試、白盒測試 3.其他&#xff1a;冒煙測試(冒煙測試主要是在開發提測后進行&#xff0c;主要是測試主流…

RAG系統實戰:當檢索為空時,如何實現生成模塊的優雅降級(Fallback)?

目錄 RAG系統實戰&#xff1a;當檢索為空時&#xff0c;如何實現生成模塊的優雅降級&#xff08;Fallback&#xff09;&#xff1f; 一、為什么需要優雅降級&#xff08;Fallback&#xff09;&#xff1f; 二、常用的優雅降級策略 策略一&#xff1a;預設后備提示&#xff0…

spring boot前后端開發上傳文件時報413(Request Entity Too Large)錯誤的可能原因及解決方案

可能原因及解決方案 1. Spring Boot默認文件大小限制 原因&#xff1a;Spring Boot默認單文件最大為1MB&#xff0c;總請求體限制為10MB。解決方案&#xff1a; 在application.properties中配置&#xff1a;spring.servlet.multipart.max-file-size10MB # 單文件最大 spring…

Qt - findChild

findChild 1. 函數原型2. 功能描述3. 使用場景4. 示例代碼5. 注意事項6. 總結 在 Qt 中&#xff0c;每個 QObject 都可以擁有子對象&#xff0c;而 QObject 提供的模板函數 findChild 就是用來在對象樹中查找滿足特定條件的子對象的工具。下面我們詳細介紹一下它的使用和注意事…

Sink Token

論文&#xff1a;ICLR 2025 MLLM視覺VAR方法Attention重分配 Sink Token 是一種在語言模型(LLM)和多模態模型(MLLM)中用于優化注意力分配的關鍵機制&#xff0c;通過吸收模型中冗余的注意力權重&#xff0c;確保注意力資源不被無效或無關信息占用。以下是對這一概念的系統性解…

Spring Event 觀察者模型及事件和消息隊列之間的區別筆記

Spring Event觀察者模型&#xff1a;基于內置事件實現自定義監聽 在Spring框架中&#xff0c;觀察者模式通過事件驅動模型實現&#xff0c;允許組件間通過事件發布與監聽進行解耦通信。這一機制的核心在于ApplicationEvent、ApplicationListener和ApplicationEventPublisher等接…

【復活吧,我的愛機!】Ideapad300-15isk拆機升級:加內存條 + 換固態硬盤 + 換電源

寫在前面&#xff1a;本博客僅作記錄學習之用&#xff0c;部分圖片來自網絡&#xff0c;如需引用請注明出處&#xff0c;同時如有侵犯您的權益&#xff0c;請聯系刪除&#xff01; 文章目錄 前言升級成本升級流程電池健康度加內存條和換內存條光驅位加裝機械硬盤更換電池重裝系…

基于PyQt5的自動化任務管理軟件:高效、智能的任務調度與執行管理

基于PyQt5的自動化任務管理軟件&#xff1a;高效、智能的任務調度與執行管理 相關資源文件已經打包成EXE文件&#xff0c;可雙擊直接運行程序&#xff0c;且文章末尾已附上相關源碼&#xff0c;以供大家學習交流&#xff0c;博主主頁還有更多Python相關程序案例&#xff0c;秉著…

JavaScript 庫:全面解析與推薦

JavaScript 庫:全面解析與推薦 引言 JavaScript 作為當今最流行的前端開發語言之一,擁有豐富的庫和框架。這些庫和框架極大地簡化了開發工作,提高了開發效率。本文將全面解析 JavaScript 庫,并推薦一些優秀的庫,幫助開發者更好地掌握 JavaScript。 JavaScript 庫概述 …

C#從入門到精通(5)

目錄 第十二章 其他基礎知識 &#xff08;1&#xff09;抽象類和方法 &#xff08;2&#xff09;接口 &#xff08;3&#xff09;集合與索引器 &#xff08;4&#xff09;委托和匿名方法 &#xff08;5&#xff09;事件 &#xff08;6&#xff09;迭代器 &#xff08;7…

【區塊鏈安全 | 第十四篇】類型之值類型(一)

文章目錄 值類型布爾值整數運算符取模運算指數運算 定點數地址&#xff08;Address&#xff09;類型轉換地址成員balance 和 transfersendcall&#xff0c;delegatecall 和 staticcallcode 和 codehash 合約類型&#xff08;Contract Types&#xff09;固定大小字節數組&#x…

Windows 系統下多功能免費 PDF 編輯工具詳解

IceCream PDF Editor是一款極為實用且操作簡便的PDF文件編輯工具&#xff0c;它完美適配Windows操作系統。其用戶界面設計得十分直觀&#xff0c;哪怕是初次接觸的用戶也能快速上手。更為重要的是&#xff0c;該軟件具備豐富多樣的強大功能&#xff0c;能全方位滿足各類PDF編輯…

vue3相比于vue2的提升

性能提升&#xff1a; Vue3的頁面渲染速度更快、性能更好。特別是在處理大量數據和復雜組件時&#xff0c;優勢更加明顯。Vue3引入了編譯時優化&#xff0c;如靜態節點提升&#xff08;hoistStatic&#xff09;、補丁標志&#xff08;patchflag&#xff09;等&#xff0c;這些…

Redis 梳理匯總目錄

Redis 哨兵集群&#xff08;Sentinel&#xff09;與 Cluster 集群對比-CSDN博客 如何快速將大規模數據保存到Redis集群-CSDN博客 Redis的一些高級指令-CSDN博客 Redis 篇-CSDN博客

【奇點時刻】GPT-4o新生圖特性深度洞察報告

以下報告圍繞最新推出的「GPT4o」最新圖像生成技術展開&#xff0c;旨在讓讀者從整體層面快速了解其技術原理、功能亮點&#xff0c;以及與其他常見圖像生成或AI工具的對比分析&#xff0c;同時也會客觀探討該技術在應用過程中可能遇到的挑戰與限制。 1. 技術背景概述 GPT4o新…

【算法day28】解數獨——編寫一個程序,通過填充空格來解決數獨問題

37. 解數獨 編寫一個程序&#xff0c;通過填充空格來解決數獨問題。 數獨的解法需 遵循如下規則&#xff1a; 數字 1-9 在每一行只能出現一次。 數字 1-9 在每一列只能出現一次。 數字 1-9 在每一個以粗實線分隔的 3x3 宮內只能出現一次。&#xff08;請參考示例圖&#xff…

【已解決】Javascript setMonth跨月問題;2025-03-31 setMonth后變成 2025-05-01

文章目錄 bug重現解決方法&#xff1a;用第三方插件來實現&#xff08;不推薦原生代碼來實現&#xff09;。項目中用的有dayjs。若要自己實現&#xff0c;參考 AI給出方案&#xff1a; bug重現 今天&#xff08;2025-04-01&#xff09;遇到的一個問題。原代碼邏輯大概是這樣的…

力扣刷題-熱題100題-第29題(c++、python)

19. 刪除鏈表的倒數第 N 個結點 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/remove-nth-node-from-end-of-list/description/?envTypestudy-plan-v2&envIdtop-100-liked 計算鏈表長度 對于鏈表&#xff0c;難的就是不知道有多少元素&#xff…

【QT】QT的多界面跳轉以及界面之間傳遞參數

QT的多界面跳轉以及界面之間傳遞參數 一、在QT工程中添加新的界面二、多界面跳轉的兩種情況1、A界面跳到B界面&#xff0c;不需要返回2、A界面跳到B界面&#xff0c;需要返回1&#xff09;使用this指針傳遞將當前界面地址傳遞給下一界面2&#xff09;使用parentWidget函數獲取上…

【力扣hot100題】(022)反轉鏈表

非常經典&#xff0c;我寫的比較復雜&#xff0c;一直以來的思路都是這樣&#xff0c;就沒有去找更簡單的解法&#xff1a;&#xff08;做鏈表題習慣加頭結點的前置節點了&#xff0c;去掉也行&#xff09; /*** Definition for singly-linked list.* struct ListNode {* …