C++學習之路:指針基礎

目錄

  • 指針介紹與基本用法
  • 雙重指針
  • 函數指針
  • 空指針與野指針
  • 函數參數的指針傳遞
  • 最后

指針一般在C/C++語言學習的后期接觸,這樣就導致指針給新手一種高深莫測、難以掌握的刻板印象。但實際上指針的使用很簡單,并且還能夠極大的提高程序的靈活性,幫助我們輕松實現復雜的功能。

指針介紹與基本用法

?指針是什么?和上一章將的變量一樣,指針也是一種變量罷了。與普通變量不同的是,指針變量存儲的內容是地址數據,像什么0xffee之類的十六進制數據,并且它也有自己的地址,可以通過取地址符號&進行取址。下面這個代碼定義了一個空指針a并且輸出a的地址:

#include<iostream>
#include <cstring>
using namespace std;int main(){
char* a = NULL; 
cout << &a <<endl; //輸出0xe3c49ff878
return 0;
}

?指針也是一個變量,就像int類型里面存儲整數,float存儲小數一樣,指針也有自己的使命:存儲其他變量的地址。因此,不能給指針賦數字或者字符,指針內只能裝載其它變量的地址數據。
?指針的語法為:type * ptr_name例如int * a;float *b等啊,前面的type表明了這個指針存儲的地址值對應的變量的類型。int類型就只能存儲int類型變量的地址,float類型就只能存儲float類型變量的地址。

#include<iostream>
#include <cstring>
using namespace std;int main(){int a = 1;float b = 0.01;int * i_Ptr = &a;float * f_Ptr = &b;char* c_Ptr = &a ; //報錯:"int *" 類型的值不能用于初始化 "char *" 類型的實體C/C++(144)
return 0;
}

?指針使用的精髓與最強大的地方在于取值符*,通過*實現了根據地址找到指針指向的變量。這個功能真的很振奮人心,是int,float等其他變量類型所沒有的功能。看下面這個例子,*ptr = variable

#include<iostream>
#include <cstring>
using namespace std;int main(){int a = 1;float b = 0.01;int * i_Ptr = &a;float * f_Ptr = &b;//通過*,找到了對應地址的變量a,bcout << *i_Ptr <<endl;  //輸出:1cout << *f_Ptr <<endl;  //輸出 0.01//再通過地址來修改對應變量的值,此時*i_Ptr = a,*f_Ptr = b*i_Ptr = 2; *f_Ptr = 0.02;cout <<a <<endl; //輸出2cout <<b<<endl; //輸出0.02
return 0;
}

?為了進一步說明取值符*的作用,繪圖一張如下:揭示了指針的指向變量的功能
在這里插入圖片描述

雙重指針

?上面這張圖最后出現了一個指向指針的指針,我們也稱這種指針叫雙重指針(另外還有三重、四重等,學會了雙重指針其余的都是一樣的)。雙指針即指針內存儲的值(指向的變量的地址)是另一個指針的地址。例如上圖的d,有d=&p,則*d = p。
?雙指針的作用在于,通過雙指針(d)可以在函數中調用以及修改指針(p)指向的變量(通過*d = p這個方法可以修改指針p的值從而改變指向對象,以及**d = *p =a,從而修改指針p指向的變量a的值)
下面這個是通過**d修改雙重指針指向的指針(b)所指向的對象(a)的值,把a的值改成了10

 #include<iostream>
using namespace std;
void func1(float** d){**d = 10; //通過**d改變指針指向對象的值
}
int main(){float a = 1;float *b = &a;func1(&b); cout << a<<endl; //輸出a=10,即通過**d = a實現修改指向指針的值return 0;
}

下面這個是通過*d修改雙重指針指向的指針(b)所指向的對象(a),把指向的對象從a轉成了b

#include<iostream>
using namespace std;
float c = 2;
void func1(float** d){*d = &c; //通過*d改變指針指向的對象
}
int main(){float a = 1;float *b = &a; //此時 b指向afunc1(&b);  //函數更改了b指向的對象cout << *b <<endl; //輸出2,即通過*d = b,實現修改指向指針所指向的對象;return 0;
}

函數指針

?函數指針顧名思義就是指向一個函數的指針,通過函數指針可以調用函數。事實上,函數名本身就是一個函數指針,其存儲著函數的入口地址,寫一段小試驗打印函數指針地址內容如下:

#include<iostream>
using namespace std;void func1(int a,int b)
{cout << (a+b) <<endl;
}int main()
{cout << (void*)func1 <<endl; //輸出0x7ff701251450return 0;
}

?函數指針主要由函數返回值類型以及函數參數類型來定義。語法為返回值類型(*指針名)(參數1類型,參數2類型...)
例如指向前面代碼片段的函數指針可以被定義為void(*p)(int,int)。函數指針存儲函數入口地址,最大的功能就是將函數作為參數傳入另一個函數,示例如下:

#include<iostream>
using namespace std;void func1(int a,int b)
{cout << (a+b) <<endl;
}void func2(void (*f)(int,int),int c)
{f(1,3);cout << c <<endl;
}int main()
{void(*p)(int,int);p = func1;func2(p,3);  //輸出 4 3//直接func2(func1,3)也行return 0;
}

空指針與野指針

?空指針是指不指向任何變量的指針,C++中常用NULL宏來對其進行定義。空指針的作用就是初始化指針,例如在進行內存分配前,我們可能需要先把指針給定義出來,此時空指針不指向任何對象,被初始化為0。來看這樣一個例子:

#include<iostream>
using namespace std;
int main(){int* a; //野指針cout<< a <<endl; //輸出0x7f6de082ba50cout<< *a <<endl; //輸出 2int* b = NULL; //空指針cout<<b<<endl; //輸出0cout<<*b <<endl; //輸出Segmentation fault (core dumped)return 0;
}

?我們把未初始化,或者指向無效對象的指針叫做野指針,例如上面例子中的指針a。a指向了一個完全隨機的內存位置,這樣就有可能造成越界訪問的問題,進而導致程序崩潰。反觀指針b被定義為空指針,其值為0,并且如果此時訪問空指針,操作系統會報錯,對內存數據進行保護,減小了程序崩潰的風險。

函數參數的指針傳遞

?指針的一個重要的應用就是函數參數的指針傳遞,即傳入函數的參數不是變量本身而是變量的地址。如果傳入的是變量那么這種傳參方式叫值傳遞,編譯器會拷貝一份參數值到函數內部。這樣一來是無法修改對應的變量,因為只傳入了值,沒有對應地址;二來拷貝需要占用內存空間。
通過指針傳遞的方法,可以在不使用返回值的前提下(使用返回值的方法會產生數據拷貝增大函數內存開銷),通過取值操作符*來直接改變變量的值。并且由于傳入的是變量地址,并不會函數本身不會占用太多的內存空間。二者對比的測試函數如下:

#include<iostream>
using namespace std;
float c = 2;//值傳遞
void func1(float d){d = 10; //實際上只是函數內部創建了一個局部變量float d;
}
//指針傳遞
void func2(float* d){*d = 10; //通過*d改變指針指向的對象
}int main(){float a = 1;float *b = &a; //此時 b指向afunc1(a);cout << a <<endl; //輸出 a = 1,并沒有改變a的值。func2(&a);  //函數可以直接改變a的值cout << a <<endl; //輸出10,即修改指向指針所指向的對象的值;return 0;
}

雙重指針的作用也是類似,可以實現在函數中改變傳入的指針變量,例如改變指向對象,改變內存分配等。上一節雙重指針的兩個實例可以仔細研讀一下。這里給一個通過雙重指針實現自定義內存分配的例子:

#include<iostream>
using namespace std;
float c = 2;//函數功能:為指針分配內存空間
void func1(float **d){*d = new float[2]; //*d相當于傳入的指針a
}int main(){float *a = NULL;//定義了一個空指針cout <<a[1]<<endl; //越界訪問,程序出錯func1(&a); cout << a[1] <<endl; //輸出一個隨機值return 0;
}

最后

?最后想說一下,關于指針上面的內容只是基礎,后續還有關于指針數組和數組指針的一些內容,我將會放在數組那一章再介紹。

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

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

相關文章

【服務日志鏈路追蹤】

MDCInheritableThreadLocal和spring cloud sleuth 在微服務架構中&#xff0c;日志鏈路追蹤&#xff08;Logback Distributed Tracing&#xff09; 是一個關鍵需求&#xff0c;主要用于跟蹤請求在不同服務間的調用鏈路&#xff0c;便于排查問題。常見的實現方案有兩種&#x…

Kafka+Zookeeper從docker部署到spring boot使用完整教程

文章目錄 一、Kafka1.Kafka核心介紹&#xff1a;?核心架構?核心特性?典型應用 2.Kafka對 ZooKeeper 的依賴&#xff1a;3.去 ZooKeeper 的演進之路&#xff1a;注&#xff1a;&#xff08;本文采用ZooKeeper3.8 Kafka2.8.1&#xff09; 二、Zookeeper1.核心架構與特性2.典型…

JUC系列JMM學習之隨筆

JUC: JUC 是 Java 并發編程的核心工具包,全稱為 Java Util Concurrent,是 java.util.concurrent 包及其子包的簡稱。它提供了一套強大且高效的并發編程工具,用于簡化多線程開發并提高性能。 CPU核心數和線程數的關系:1核處理1線程(同一時間單次) CPU內核結構: 工作內…

The Rust Programming Language 學習 (九)

泛型 每一個編程語言都有高效處理重復概念的工具。在 Rust 中其工具之一就是 泛型&#xff08;generics&#xff09;。泛型是具體類型或其他屬性的抽象替代。我們可以表達泛型的屬性&#xff0c;比如他們的行為或如何與其他泛型相關聯&#xff0c;而不需要在編寫和編譯代碼時知…

藍橋杯 混乘數字

問題描述 混乘數字的定義如下&#xff1a; 對于一個正整數 n&#xff0c;如果存在正整數 a 和 b&#xff0c;使得&#xff1a; n a b且 a 與 b 的十進制數位中每個數字出現的次數之和&#xff0c;與 n 中對應數字出現的次數相同&#xff0c;則稱 n 為混乘數字。 示例 對于…

CExercise04_1位運算符_2 定義一個函數判斷給定的正整數是否為2的冪

題目&#xff1a; 給定一個正整數&#xff0c;請定義一個函數判斷它是否為2的冪(1, 2, 4, 8, 16, …) 分析&#xff1a; &#xff1a; 代碼 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdbool.h>/* 給定一個正整數&#xff0c;請定義一個函數…

SSL證書不可信的原因有哪些?(國科云)

SSL證書用于在客戶端和服務器端之間建立一條加密通道&#xff0c;確保數據在傳輸過程中的安全性和完整性。然而&#xff0c;在實際應用中&#xff0c;我們有時會遇到SSL證書不可信的情況&#xff0c;嚴重影響了用戶對網站的信任度。那么&#xff0c;SSL證書不可信的原因究竟有哪…

[王陽明代數講義]琴語言類型系統工程特性

琴語言類型系統工程特性 層展物理學組織實務與藝術與琴生生.物機.械科.技工.業研究.所軟凝聚態物理開發工具包社會科學氣質砥礪學人生意氣場社群成員魅力場與心氣微積分社會關系力學 意氣實體過程圖論信息編碼&#xff0c;如來碼導引 注意力機制道裝Transformer架構的發展標度律…

自抗擾ADRC之二階線性擴展狀態觀測器(LESO)推導

1.龍伯格觀測器 實際工程應用中&#xff0c;狀態變量有時難以使用傳感器直接測量&#xff0c;在這種情況下&#xff0c;使用狀態觀測器估計系統實際狀態是非常常見的做法。最出名的狀態觀測器當屬龍伯格博士在1971年發表于TAC的An Introduction to Observer[1]一文中提出的基于…

從頭開發一個Flutter插件(二)高德地圖定位插件

開發基于高德定位SDK的Flutter插件 在上一篇文章里具體介紹了Flutter插件的具體開發流程&#xff0c;從創建項目到發布。接下來將為Flutter天氣項目開發一個基于高德定位SDK的Flutter定位插件。 申請key 首先進入高德地圖定位SDK文檔內下載定位SDK&#xff0c;并按要求申請A…

分布式鎖之redis6

一、分布式鎖介紹 之前我們都是使用本地鎖&#xff08;synchronize、lock等&#xff09;來避免共享資源并發操作導致數據問題&#xff0c;這種是鎖在當前進程內。 那么在集群部署下&#xff0c;對于多個節點&#xff0c;我們要使用分布式鎖來避免共享資源并發操作導致數據問題…

ubuntu中使用安卓模擬器

本文這里介紹 使用 android studio Emulator &#xff0c; 當然也有 Anbox (Lightweight)&#xff0c; Waydroid (Best for Full Android Experience), 首先確保自己安裝了 android studio &#xff1b; sudo apt update sudo apt install openjdk-11-jdk sudo snap install…

二語習得理論(Second Language Acquisition, SLA)如何學習英語

二語習得理論&#xff08;Second Language Acquisition, SLA&#xff09;是研究學習者如何在成人或青少年階段學習第二語言&#xff08;L2&#xff09;的理論框架。該理論主要關注語言習得過程中的認知、社會和文化因素&#xff0c;解釋了學習者如何從初學者逐漸變得流利并能夠…

WinDbg. From A to Z! 筆記(下)

原文鏈接: WinDbg. From A to Z! 文章目錄 使用WinDbg臨界區相關命令示例 -- 查看臨界區其他有用的命令 WinDbg中的偽寄存器自動偽寄存器 WinDbg中的表達式其他操作默認的表達式計算方式 WinDbg中的重命名調試器命令語言編程控制流命令程序執行 WinDbg 遠程調試事件監控WinDbg …

RainbowDash 的旅行

D RainbowDash 的旅行 - 第七屆校賽正式賽 —— 補題 題目大意&#xff1a; 湖中心有一座島&#xff0c;湖的外圍有 m m m 間木屋&#xff08;圍繞小島&#xff09; &#xff0c;第 i i i 間木屋和小島之間有 a i a_i ai? 座 A A A 類橋&#xff0c; b i b_i bi? 座 B …

MySQL-SQL-DDL語句、表結構創建語句

一.SQL SQL&#xff1a;一門操作關系型數據庫的編程語言&#xff0c;定義操作所有關系型數據庫的統一標準 二. DDL-數據庫 1. 查詢所有數據庫 命令&#xff1a;show databases; 2. 查詢當前數據庫 命令&#xff1a;select database(); 3. 創建數據庫 命令&#xff1a;create da…

Sora結構猜測

方案&#xff1a;VAE Encoder&#xff08;視頻壓縮&#xff09; -> Transform Diffusion &#xff08;從視頻數據中學習分布&#xff0c;并根據條件生成新視頻&#xff09; -> VAE Decoder &#xff08;視頻解壓縮&#xff09; 從博客出發&#xff0c;經過學術Survey&am…

TortoiseSVN設置忽略清單

1.TortoiseSVN > Properties&#xff08;如果安裝了 TortoiseSVN&#xff09;。 2. 在彈出的屬性窗口中&#xff0c;點擊 New > Other。 4. 在 Property name 中輸入 svn:ignore 。 5. 在 Property value 中輸入要忽略的文件夾或文件名稱&#xff0c;例如&#xff1a; #…

深入解析Java哈希表:從理論到實踐

哈希表&#xff08;Hash Table&#xff09;是計算機科學中最重要的數據結構之一&#xff0c;也是Java集合框架的核心組件。本文將以HashMap為切入點&#xff0c;深入剖析Java哈希表的實現原理、使用技巧和底層機制。 一、哈希表基礎原理 1. 核心概念 鍵值對存儲&#xff1a;通…

leetcode:1582. 二進制矩陣中的特殊位置(python3解法)

難度&#xff1a;簡單 給定一個 m x n 的二進制矩陣 mat&#xff0c;返回矩陣 mat 中特殊位置的數量。 如果位置 (i, j) 滿足 mat[i][j] 1 并且行 i 與列 j 中的所有其他元素都是 0&#xff08;行和列的下標從 0 開始計數&#xff09;&#xff0c;那么它被稱為 特殊 位置。 示…