C語言——深入理解指針(1)

目錄

1.內存與地址

1.1 什么是內存

1.2 編址

2. 指針的變量和地址

2.1 取地址(&)

2.2 指針變量

2.3 解引用

2.4?指針變量大小

3. 指針變量類型存在的意義

3.1 不同類型指針的解引用

3.2 指針對整數的運算(+,-)

3.3 void* 指針

4. const 修飾

4.1 const 變量

?4.2 const(指針變量)

5. 指針的運算

?6. 野指針

7. assert斷言

8.指針的使用和傳址調用

舉例1:strlen 的模擬實現

傳址調用例如:寫?個函數,交換兩個整型變量的值


1.內存與地址

1.1 什么是內存

在這之前我們先說一下生活中的一些與內存非常像的例子

生活中有很多高樓,假設樓里有100個房間,你就住在其中一個,你的朋友要來找你,如果房間沒有編號,那么就要一間一間去找,這樣等你的朋友找到你,大概也天黑了,但是如果每個房間都有自己的編號,如:一樓:101,102.......? ? ? ? 二樓:201,202.....以此類推,這樣你的朋友就可以快速找到你。

?其實計算機中的內存也是通過這樣管理的,我們知道計算機CPU在處理數據的時候,需要的數據是在內存中讀取的,用完了在放回內存中。

計算機也是把內存劃分為一個個的內存單元,每個內存單元的大小是1字節。

補充:一個比特位可以儲存一個2進制的位1或0。

bit- 比特位                    1byte = 8bit
byte- 字節                    1KB = 1024byte
KB                            1MB = 1024KB
MB                            1GB = 1024MB
GB                            1TB = 1024GB
TB                            1PB = 1024TB
PB

把這些每一個內存單元想成一個房間,一個房間可以放8個比特位。

把每個內存單元的編號想成一個內存的地址。

總結就是:內存單元的編號==地址==指針

1.2 編址

計算機中的編址,不是把每個字節的地址記錄下來,而是通過硬件設計來完成的。就比如許多樂器的規則,都是設計者設計好的,所有人都遵循這個規則。其實本質上就是一直約定出來的共識。

2. 指針的變量和地址

2.1 取地址(&)

知道了內存和地址,其實在C語言中創建變量就是向內存申請一塊空間。

?向這樣的地址a我們應該如何得呢?

這時就要用到我們的一個操作符(&)——取地址操作符

#include <stdio.h>
//%p--打印地址
int main()
{int a = 10;printf("%p\n", &a);return 0;
}

?我們知道整型變量是占4個字節,這里我們只要知道第一個地址,就可以訪問到4個字節的數據了

2.2 指針變量

當我們通過&得到的地址也是一個數(0x0023DF32),這個數值有時候也要儲存起來,方便我們后面的使用。但是我們應該存放到哪呢?答案就是:指針變量。

#include <stdio.h>
int main()
{int a = 10;int* p = &a;//把a的地址儲存在p這個指針變量中。return 0;
}

注意:指針變量也是變量,這種變量是用來存地址的,只要存放在指針中的值都會理解為地址。

?指針的類型:

int a=10;
int* p=&a;

這里的* 是在說明平時指針變量,而int 是在說明p指向的是整型類型的對象。

2.3 解引用

我們現在知道怎么把地址保證起來了,但是要怎么使用呢?在現實生活中,我們每個房間都會有一把打開它的鑰匙,用了鑰匙我們就可以打開房間,找到里面的東西。C語言其實也是一樣的,我們拿到了地址,就可以通過地址找到地址指向的對象。這里就要用到解引用操作符 *()。

#include <stdio.h>
int main()
{int a = 10;int* p = &a;//把a的地址儲存在p這個指針變量中。*p = 0;//解引用p,找到a并且將它的值改為0printf("%d", *p);return 0;
}

2.4?指針變量大小

#include <stdio.h>
//指針變量的??取決于地址的??
//32位平臺下地址是32個bit位(即4個字節)
//64位平臺下地址是64個bit位(即8個字節)
int main()
{printf("%zd\n", sizeof(char*));printf("%zd\n", sizeof(short*));printf("%zd\n", sizeof(int*));printf("%zd\n", sizeof(double*));return 0;
}

3. 指針變量類型存在的意義

?其實指針類型是有特殊意義的,不同的類型有不同的意義。

3.1 不同類型指針的解引用

我們先看兩個程序:

#include <stdio.h>
int main()
{int n = 0x11223344;int* pi = &n;*pi = 0;return 0;
}
#include <stdio.h>
int main()
{int n = 0x11223344;char* pc = (char*)&n;*pc = 0;return 0;
}

通過調試我們發現第一個程序會把n的4個字節全部改為0,而第二個程序只會把第一個字節改為0

總結:指針的類型決定了,對指針解引?的時候有多?的權限(?次能操作?個字節)

3.2 指針對整數的運算(+,-)

我們可以看到,char*類型的指針變量+1跳過1個字節,int* 類型的指針變量+1,跳過4次字節。

總結:指針的類型決定了指針向前或者向后走一步的距離。

3.3 void* 指針

在指針類型中有void*類型的,我們可以理解為沒有具體類型的指針(泛指針),這種指針可以接收任意類型的地址。但是,void* 不能用來直接進行指針的加減整數和解引用運算。

?注:?般 void* 類型的指針是使?在函數參數的部分,?來接收不同類型數據的地址,這樣的設計可以 實現泛型編程的效果。使得?個函數來處理多種類型的數據。

4. const 修飾

4.1 const 變量

只要是變量,就是可以修改的。如果我們要想要這個變量成為不可變的,那么就要用到 const 來修飾。

?4.2 const(指針變量)

舉例:

#include <stdio.h>
//代碼1
void test1()
{int n = 10;int m = 20;int* p = &n;*p = 20;p = &m; 
}
void test2()
{//代碼2int n = 10;int m = 20;const int* p = &n;*p = 20;p = &m; 
}
void test3()
{int n = 10;int m = 20;int* const p = &n;*p = 20;p = &m; 
}
void test4()
{int n = 10;int m = 20;int const* const p = &n;*p = 20; p = &m; 
}
int main()
{//測試?const修飾的情況test1();//測試const放在*的左邊情況test2();//測試const放在*的右邊情況test3();//測試*的左右兩邊都有consttest4();return 0;
}

結論:const修飾指針變量的時候

1.const如果放在*的左邊,修飾的是指針指向的內容,保證指針指向的內容不能通過指針來改變。 但是指針變量本?的內容可變。

2.const如果放在*的右邊,修飾的是指針變量本?,保證了指針變量的內容不能修改,但是指針指 向的內容,可以通過指針改變。

5. 指針的運算

指針的基本運算有三種,分別是:

?指針+- 整數——根據指針變量的類型,向前或向后移動

?指針-指針

?指針的關系運算

?6. 野指針

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

產生野指針的原因:
1. 指針沒有初始化

2. 指針越界訪問 ——只有10個元素,但是訪問到第11個

3. 指針指向的空間被釋放——指針指向函數

避免野指針的方法:
1. 指針初始化:指針一定要指向一個地址,沒有就給指針賦值NULL(0)

2.小心指針越界:?個程序向內存申請了哪些空間,通過指針也就只能訪問哪些空間。

3. 指針變量不再使用時一定要及時置為NULL,指針使用之前檢查有效性。

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

7. assert斷言

assert.h 頭?件定義了宏 assert() ,?于在運?時確保程序符合指定條件,如果不符合,就報錯終?運?。這個宏常常被稱為“斷?”。

assert (p!=NULL)
//驗證p是否等于NULL
//當p不等于NULL時,程序繼續運行,否則停止,并且給出報錯信息

assert 的實現:assert() 宏接受?個表達式作為參數。如果該表達式為真(返回值?零),assert() 不會產? 任何作?,程序繼續運?。如果該表達式為假(返回值為零), assert() 就會報錯,在標準錯誤流 stderr 中寫??條錯誤信息,顯示沒有通過的表達式,以及包含這個表達式的?件名和?號。

使用的優點:可以自動標識文件和出問題的行號,還有?種?需更改代碼就能開啟或關閉 assert() 的機制。

補充:如果已經確認程序沒有問題,不需要再做斷?,就在 #include 語句的前?,定義?個宏 NDEBUG

8.指針的使用和傳址調用

舉例1:strlen 的模擬實現

#include<assert.h>
int my_strlen(const char* str)
{int count = 0;assert(str);//斷言判的str是否為真(非0)while (*str){count++;str++;}return count;
}
int main()
{int len = my_strlen("abcdef");printf("%d\n", len);return 0;
}

傳址調用
例如:寫?個函數,交換兩個整型變量的值

我們一般的想法(傳值調用):

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

如果把要交換值的地址傳給函數呢?

我們可以看到交換成功了。這種把變量的地址傳遞給了函數的方式叫:傳址調用

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

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

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

相關文章

(10)ATF MMU轉換表

MMU簡介 MMU&#xff08;內存管理單元&#xff09;負責將軟件使用的虛擬地址轉換為內存系統中使用的物理地址。MMU包括兩個模塊&#xff1a;TLB&#xff08;Translation Lookaside Buffer&#xff09;和TWU&#xff08;Table Walk Unit&#xff09;。TLB緩存最近使用的轉換&am…

Spring Beans;Spring Bean的生命周期;spring Bean的作用域,spring處理線程并發問題

文章目錄 Spring Beans請解釋Spring Bean的生命周期解釋Spring支持的幾種bean的作用域Spring容器中的bean可以分為5個范圍&#xff1a; Spring如何處理線程并發問題&#xff1f; 在現在的項目開發中經常使用到spring bean&#xff0c;那么來談談spring bean的生命周期&#xff…

APP軟件線上排查方法

在線上環境中排查APP軟件的問題是一項關鍵任務&#xff0c;需要使用一系列方法和工具來識別、定位和解決問題。以下是一些建議的排查方法&#xff0c;希望對大家有所幫助。北京木奇移動技術有限公司&#xff0c;專業的軟件外包開發公司&#xff0c;歡迎交流合作。 1.監控和日志…

linux如何查看文件的hash數值

在Linux系統中&#xff0c;你可以使用各種工具來查看文件的哈希值。下面是一些常見的方法&#xff1a; md5sum命令&#xff1a; md5sum 文件名例如&#xff1a; md5sum example.txtsha1sum命令&#xff1a; sha1sum 文件名例如&#xff1a; sha1sum example.txtsha256sum命令&a…

SQLServer的常用數據類型

常用數據類型 關于數據類型大家可能并不陌生&#xff0c;因為我們在C#中學了常用的數據類型&#xff0c;在數據庫中其實也差不多&#xff0c;大部分都有對應關系的&#xff0c;只是關鍵字上有差別&#xff0c;接下來我們講一下&#xff0c;請大家記住常用的就行。 第一、文本…

代碼規范有用嗎?聽聽100W年薪谷歌大佬怎么說!

谷歌內部的 python 代碼規范 熟悉 python 一般都會努力遵循 pep8 規范&#xff0c;也會有一些公司制定內部的代碼規范。大公司制定規范的目的不是說你一定要怎樣去使用編程語言&#xff0c;而是讓大家遵守同一套規則&#xff0c;節省其他人閱讀代碼的成本&#xff0c;方便協作…

紅酒按照糖含量怎么分類?

我們常聽人們形容葡萄酒為干型或甜型&#xff0c;這指的是葡萄酒的含糖量。不含糖就是干型&#xff0c;含糖少就是半干型&#xff0c;含糖多就是甜型&#xff0c;這是葡萄酒分類的一種——按糖量分。云倉酒莊的品牌雷盛紅酒分享一般分為干型、半干型、半甜型、甜型四種。 云倉…

get data from Nacos error,dataId:服務名

2023-11-23 09:44:35.595 ERROR 169 — [ main] c.a.n.client.config.impl.ClientWorker : [fixed-100.66.12.65_8848] [sub-server-error] no right, dataIdcampaign-task-service, groupcampaign, tenant 2023-11-23 09:44:35.598 ERROR 169 — [ main] c.a.c.n.c.NacosPrope…

Jetson orin(Ubuntu20.04)不接顯示器無法輸出VNC圖像解決辦法以及vnc安裝記錄

sudo apt install vino 好像Jetpack 5.0中已經自帶了。。 配置VNC server: gsettings set org.gnome.Vino prompt-enabled false gsettings set org.gnome.Vino require-encryption false 編輯org.gnome,增加一個“enabled key”的參數&#xff1a; cd /usr/share/glib-2…

氮化鎵的晶體學濕式化學蝕刻法

引言 目前&#xff0c;大多數III族氮化物的加工都是通過干法等離子體蝕刻完成的。干法蝕刻有幾個缺點&#xff0c;包括產生離子誘導損傷和難以獲得激光器所需的光滑蝕刻側壁。干法蝕刻產生的側壁典型均方根(rms)粗糙度約為50納米&#xff0c;雖然已經發現KOH基溶液可以蝕刻AlN…

Android:Google三方庫之Firebase集成詳細步驟(三)

Cloud Messaging 1、清單文件配置 a、&#xff08;可選&#xff09;一項擴展 FirebaseMessagingService 的服務。除了接收通知外&#xff0c;如果您還希望在后臺應用中進行消息處理&#xff0c;則必須添加此服務。例如&#xff0c;您需要在前臺應用中接收通知、接收數據載荷以及…

服務臺需要跟蹤的3個重要指標MTBF+MTTF+MTTR

衡量標準是IT服務管理的核心&#xff0c;可提供有關運營的見解&#xff0c;并幫助確定需要持續改進的領域。通常的服務臺指標有助于展示內部運營效率。例如&#xff0c;衡量在規定時間內解決問題的工單數量的 SLA 是展示服務臺效率的關鍵因素。另一方面&#xff0c;故障指標可幫…

阿里云服務器(vgn7i-vws) anaconda(py39)+pytorch1.12.0(cu113)

安裝anaconda 2022 10 py3.9 wget https://repo.anaconda.com/archive/Anaconda3-2022.10-Linux-x86_64.sh sha256sum Anaconda3-2022.10-Linux-x86_64.sh #校驗數據完整性 chmod ux Anaconda3-2022.10-Linux-x86_64.sh #添加執行權限 bash Anaconda3-2022.10-Linux-x86_…

ate測試原理及ate測試系統(軟件)知識科普 -納米軟件

ATE(Automatic Test Equipment)測試也叫自動化測試&#xff0c;通過計算機控制測試儀器對被測對象進行測試。以計算機編程代替人工測試&#xff0c;基于測試程序控制儀器并對待測品進行輸入和輸出信號檢測分析&#xff0c;從而判斷待測品的性能是否符合要求。 ATE測試需要根據測…

linux進程調度(一)-進程概述

一、什么是進程 進程是指計算機已運行的程序。程序本身只是指令、數據及其組織形式的描述。進程就是一個程序的執行實例&#xff0c;也就是正在執行的程序。在linux操作系統的中&#xff0c;進程就是一個擔當分配系統資源CPU時間、內存的實體。進程控制的主要功能是對系統中的所…

Kafka報錯under-replicated partitions

1 under-replicated partitions異常原因 Kafka報錯under replicated partitions意味著某些分區的副本數量未達到預期的復制因子。 主要有兩種原因&#xff0c; Broker故障 如果某個Kafka Broker發生故障&#xff0c;導致其中一些分區的副本不再可用&#xff0c;那么這些分區就…

2023年微軟開源八個人工智能項目

自2001年軟件巨頭微軟前首席執行官史蒂夫鮑爾默對開源&#xff08;尤其是Linux&#xff09;發表尖刻言論以來&#xff0c;微軟正在開源方面取得了長足的進步。繼ChatGPT于去年年底發布了后&#xff0c;微軟的整個2023年&#xff0c;大多數技術都是面向開發人員和研究人員公開發…

Towhee介紹

官方網站&#xff1a;Towhee | Home - Towhee Towhee 是一個尖端框架&#xff0c;旨在通過使用基于大型語言模型 &#xff08;LLM&#xff09; 的管道編排來簡化非結構化數據的處理。它具有獨特的優勢&#xff0c;可以從各種非結構化數據類型&#xff08;包括冗長的文本、圖像…

淺談進程與線程

文章目錄 一. 進程&#x1f34e;什么是程序&#xff1f;什么是進程&#xff1f;&#x1f34b;程序的并發性和并行性&#x1f349;進程誕生的原因&#x1f351;PCB 二. 線程&#x1f365;什么是線程&#xff1f;&#x1f366;為什么引入線程&#xff1f; 三. 進程與線程的區別與…

HarmonyOS 設備管理開發:USB 服務開發指導

基本概念 USB 服務是應用訪問底層的一種設備抽象概念。開發者根據提供的 USB API&#xff0c;可以獲取設備列表、控制設備訪問權限、以及與連接的設備進行數據傳輸、控制命令傳輸等。 運作機制 USB 服務系統包含 USB API、USB Service、USB HAL。 圖 1 USB 服務運作機制 ●…