【C語言】--指針超詳解(三)

目錄

一.數組名的理解

二.使用指針訪問數組

三.一維數組傳參的本質?

四.冒泡排序

五.二級指針?

六.指針數組

6.1--指針數組的定義

6.2--指針數組模擬二維數組


🔥個人主頁:@草莓熊Lotso的個人主頁

🎬作者簡介:C++方向學習者

📖個人專欄:《C語言》


一.數組名的理解

--在前面的學習中,我們使用指針訪問數組時一般會采用以下兩種形式,它們所到達的效果也是相同的。

#include <stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int* pa = &arr[0];int* pb = arr;printf("&arr[0] = %p\n", pa);printf("arr = %p\n", pb);return 0;
}

在上述代碼中我們分別使用&arr[0]和arr的方式拿到了數組的第一個元素的地址,這是因為數組名本身就是地址,而且是數組首元素的地址。

但是有兩個例外我們需要注意一下:

  • sizeof(數組名),sizeof中單獨放數組名,這?的數組名表示整個數組,計算的是整個數組的?小,單位是字節
  • &數組名,這里的數組名表示整個數組,取出的是 整個數組的地址(整個數組的地址和數組首元素的地址是有區別的)

那么我們就通過兩個例子具體分析一下吧~

例子1:

#include <stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };printf("%d\n", sizeof(arr));return 0;
}

如果arr是數組首元素的地址,那輸出的應該是4/8?,但這串代碼的輸出結果最后是40,這就證明的sizeof(數組名)計算的是整個數組的大小。

例子2:

#include <stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };printf("&arr[0]   = %p\n", &arr[0]);printf("&arr[0]+1 = %p\n", &arr[0] + 1);printf("arr       = %p\n", arr);printf("arr+1     = %p\n", arr + 1);printf("&arr      = %p\n", &arr);printf("&arr+1    = %p\n", &arr + 1);return 0;
}

我們來分步解析一下這串代碼:

  1. 我們可以發現光看&arr,arr,&arr[0]打印出來的地址并沒有任何區別,這是因為數組的起始地址也是首元素的地址,所以我們接下來對它們分別+1 來找區別。
  2. +1之后我們會發現,&arr[0]和&arr[0]+1相差4個字節,arr和arr+1 相差4個字節,但是&arr 和 &arr+1相差40個字節。
  3. 這是因為&arr[0] 和 arr 都是?元素的地址,+1就是跳過?個元素,但是&arr是數組的地址,+1 操作是跳過整個數組的。

到這里想必大家都對數組名的意義有了正確的理解,我們接著往下看吧。


二.使用指針訪問數組

--學習了前面的知識后,再結合數組的特點,我們就可以更方便的使用指針訪問數組了。

#include <stdio.h>
int main()
{int arr[10] = { 0 };//輸?int i = 0;int sz = sizeof(arr) / sizeof(arr[0]);//輸?int* p = arr;for (i = 0; i < sz; i++){scanf("%d", p + i);//scanf("%d", arr+i);//也可以這樣寫}//輸出for (i = 0; i < sz; i++){printf("%d ", *(p + i));//*(p+i)等價于*(arr+i)也可寫成arr[i]}return 0;
}

?通過上述代碼我們可知,在這里arr和p是等價的,那我們可以使用arr[i]訪問數組,是不是也可以使用p[i]呢?

答案是當然可以,其實本質上p[i]是等價于*(p+i)的,那么同理arr[i] 應該等價于 *(arr+i),數組元素的訪問在編譯器處理的時候,也是轉換成?元素的地址+偏移量求出元素的地址,然后解引?來訪問的,所以這幾個使用那個都可以正確的打印出來結果。

還有一個比較有意思的等價關系給大家分享一下,但是不推薦使用:

arr[i] == *(arr+i) == *(i+arr) == i[arr]

大家可以發現,后面兩個等價的很怪,但確實是可行的,其實就是用了交換律而已。


三.一維數組傳參的本質?

--數組我們學過了,之前也講了,數組是可以傳遞給函數的,這個小節我們討論?下數組傳參的本質。

首先從?個問題開始,我們之前都是在函數外部計算數組的元素個數,那我們可以把數組傳給?個函數后,函數內部求數組的元素個數嗎?
#include <stdio.h>
void test(int arr[])
{int sz2 = sizeof(arr) / sizeof(arr[0]);printf("sz2 = %d\n", sz2);
}
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int sz1 = sizeof(arr) / sizeof(arr[0]);printf("sz1 = %d\n", sz1);test(arr);return 0;
}

我們通過上面這串代碼的輸出結果可以看出在函數內部沒有正確獲得數組的元素個數。這就涉及到數組傳參的本質了。

之前我們學習了:數組名是數組首元素的地址;那么在數組傳參的時候,傳遞的是數組名,也就是說本質上數組傳參傳遞的是數組首元素的地址。
? ? ? ? --?所以函數形參的部分理論上應該使?指針變量來接收首元素的地址。那么在函數內部我們寫sizeof(arr)計算的是?個地址的大小(單位字節),也就是計算一個指針變量的大小,而不是數組的大小(單位字節)。正是因為函數的參數部分的本質是指針,所以在函數內部是沒辦法求數組元素個數的。
void test(int arr[])//參數寫成數組形式,本質上還是指針
{printf("%d\n", sizeof(arr));
}
void test(int* arr)//參數寫成指針形式
{printf("%d\n", sizeof(arr));//計算?個指針變量的??
}
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };test(arr);return 0;
}

?總結:一維數組傳參,形參的部分可以寫成數組的形式,也可以寫成指針的形式。


四.冒泡排序

--冒泡排序的核心思想:兩兩相鄰的元素進行比較。

//方法一
#include<stdio.h>
#include<string.h>void bubble_sort(int arr[], int sz)
{int i = 0;//趟數=元素個數-1=sz-1;for (i = 0;i < sz - 1;i++){int j = 0;//每一趟要比較的次數=元素個數-當前趟數-1=sz-i-1;for (j = 0;j < sz - i - 1;j++){if (arr[j] > arr[j + 1]){int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}
}
void print_arr(int arr[], int sz)
{for (int i = 0;i < sz;i++){printf("%d ", arr[i]);}
}
int main()
{int arr[10] = { 0 };//如果是arr[],后面就無法自己輸入數字,要注意int sz = sizeof(arr) / sizeof(arr[0]);printf("請輸入待排序的數字: ");for (int n = 0;n < sz;n++){scanf("%d", arr + n);}bubble_sort(arr, sz);printf("排序完成后的數字是: ");print_arr(arr, sz);return 0;
}
//方法二--優化
#include<stdio.h>
#include<string.h>
void bubble_sort(int arr[], int sz)
{int i = 0;//趟數=元素個數-1=sz-1;for (i = 0;i < sz - 1;i++){int j = 0;int flag = 0;//假設這趟是有序的//每一趟要比較的次數=元素個數-當前趟數-1=sz-i-1;for (j = 0;j < sz - i - 1;j++){if (arr[j] > arr[j + 1]){int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;flag = 0;//只要這趟有一次發生交換的,則無序}}if (flag == 1);//這一趟一次交換都沒發生就說明已經有序了,不用繼續排序了break;}
}
void print_arr(int arr[], int sz)
{for (int i = 0;i < sz;i++){printf("%d ", arr[i]);}
}
int main()
{int arr[10] = { 0 };//如果是arr[],后面就無法自己輸入數字,要注意int sz = sizeof(arr) / sizeof(arr[0]);printf("請輸入待排序的數字: ");for (int n = 0;n < sz;n++){scanf("%d", arr + n);}bubble_sort(arr, sz);printf("排序完成后的數字是: ");print_arr(arr, sz);return 0;
}

優化后的方法可以減少比較的次數,大大減少了程序運行的時間。


五.二級指針?

?--指針變量也是變量,是變量就有地址,那指針變量的地址存放在哪里呢。

那就是存放在二級指針里。

對于二級指針的運算有:

  • *ppa 通過對ppa中的地址進?解引?,這樣找到的是 pa *ppa 其實訪問的就是?pa 。
1? int b = 20;
2? *ppa = &b;//等價于 pa = &b;
  • **ppa 先通過 *ppa 找到 pa ,然后對 pa 進?解引?操作:*pa ,那找到的是 a?
1 **ppa = 30;
2 //等價于*pa = 30;
3 //等價于a = 30;?

六.指針數組

6.1--指針數組的定義

--我們先來思考一下指針數組是指針還是數組呢?

我們類比?下,整型數組,是存放整型的數組,字符數組是存放字符的數組。
那指針數組呢?那肯定就是存放指針的數組。

?指針數組的每個元素都是用來存放地址(指針)的。指針數組的每個元素都是地址,又可以指向一塊區域。

6.2--指針數組模擬二維數組

#include <stdio.h>
int main()
{int arr1[] = { 1,2,3,4,5 };int arr2[] = { 2,3,4,5,6 };int arr3[] = { 3,4,5,6,7 };//數組名是數組首元素的地址,類型是int*,所以可以存放在parr數組中int* parr[3] = { arr1, arr2, arr3 };int i = 0;int j = 0;for (i = 0; i < 3; i++){for (j = 0; j < 5; j++){printf("%d ", parr[i][j]);}printf("\n");}return 0;
}

parr[i]是訪問parr數組的元素,parr[i]找到的數組元素指向了整型?維數組,parr[i][j]就是整型?維數組中的元素。

上述的代碼可以模擬出二維數組的效果,實際上并非完全是二維數組,因為每一行并非是連續的。

往期回顧:

【C語言】--指針超詳解(一)

【C語言】--指針超詳解(二)

?結語:本篇文章就到此結束了,繼前面兩篇文章后在此篇文章中給大家分享了大量數組和指針之間相聯系的知識點,還有冒泡排序等,如果文章對你有幫助的話,歡迎評論,點贊,收藏加關注,感謝大家的支持,后續會繼續更新指針相關內容。

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

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

相關文章

Linux防火墻

1.防火墻是一種位于內部網絡與外部網絡之間的網絡安全系統&#xff0c;它依照特定的規則&#xff0c;允許或限制傳輸的數據通過&#xff0c;以保護內部網絡的安全。以下從功能、分類、工作原理等方面為你詳細講解&#xff1a; 功能訪問控制&#xff1a;這是防火墻最主要的功能。…

嵌入式培訓之C語言學習完(十七)結構體、共用體、枚舉、typedef關鍵字與位運算

目錄 一、結構體&#xff08;struct關鍵字&#xff09; &#xff08;一&#xff09;聲明一個結構體數據類型 &#xff08;二&#xff09;結構體的成員初始化與賦值 a、結構體變量賦值 b、結構體成員初始化 c、結構體的定義形式 &#xff08;三&#xff09;考點&#xff…

Python字典:數據操作的核心容器

在Python編程生態中&#xff0c;字典&#xff08;dict&#xff09;是最常用且功能強大的內置數據結構之一。它以鍵值對&#xff08;Key-Value Pair&#xff09;的形式存儲數據&#xff0c;為快速查找、靈活映射關系提供了天然支持。無論是數據清洗、算法實現還是Web開發&#x…

按位寬提取十六進制值

需求&#xff1a;給出一個十六進制值&#xff0c;要求提取high和low位之間的值。比如16ha0f0&#xff0c;這是一個16bit寬的十六進制數0xa0f0&#xff0c;提取[15:12]范圍內的值。 def extract_bits(value, high, low):"""從 value 中提取 [high:low] 位的值:p…

LeRobot 項目部署運行邏輯(六)——visualize_dataset_html.py/visualize_dataset.py

可視化腳本包括了兩個方法&#xff1a;遠程下載 huggingface 上的數據集和使用本地數據集 腳本主要使用兩個&#xff1a; 目前來說&#xff0c;ACT 采集訓練用的是統一時間長度的數據集&#xff0c;此外&#xff0c;這兩個腳本最大的問題在于不能裁剪&#xff0c;這也是比較好…

SSTI模版注入

1、概念 SSTI是一種常見的Web安全漏洞&#xff0c;它允許攻擊者通過注入惡意模板代碼&#xff0c;使服務器在渲染模板時執行非預期的操作。 &#xff08;1&#xff09;渲染模版 至于什么是渲染模版&#xff1a;服務器端渲染模板是一種Web開發技術&#xff0c;它允許在服務器端…

關于點膠機的精度

一、精度&#xff1a; 1:X/y軸定位精度常通在5個絲左右&#xff0c;Z軸在3個絲左右&#xff0c; 如果采用伺服電機絲桿配置&#xff0c;可提升至于個2絲左右。 2&#xff1a;膠水控制精度&#xff1a;通過噴閥驅動器&#xff0c;氣壓等參數&#xff0c;實現膠量控制&#xf…

gitee推送更新失敗問題記錄:remote: error: hook declined to update refs/heads/master

問題描述&#xff1a; gitee推送更新時&#xff0c;提示&#xff1a; 解決方法&#xff1a; 登錄Gitee&#xff0c;進入【個人主頁】 點擊【個人設置】 更改郵箱的配置&#xff0c;如下&#xff1a; 更改“禁止命令行推送暴露個人郵箱”&#xff0c;將其關閉&#xff1a;

Java如何獲取電腦分辨率?

以下是一個 Java 程序示例&#xff0c;用于獲取電腦的主屏幕分辨率&#xff1a; import java.awt.*; public class ScreenResolutionExample { public static void main(String[] args) { // 獲取默認的屏幕設備 GraphicsDevice device GraphicsEnvironm…

WPF 3D圖形編程核心技術解析

一、三維坐標系系統 WPF采用右手坐標系系統&#xff0c;空間定位遵循&#xff1a; X 軸 → 右 Y 軸 → 上 Z 軸 → 觀察方向 X軸 \rightarrow 右\quad Y軸 \rightarrow 上\quad Z軸 \rightarrow 觀察方向 X軸→右Y軸→上Z軸→觀察方向 三維坐標值表示為 ( x , y , z ) (x, y,…

【庫(Library)、包(Package)和模塊(Module)解析】

在Python中&#xff0c;**庫&#xff08;Library&#xff09;、包&#xff08;Package&#xff09;和模塊&#xff08;Module&#xff09;**是代碼組織的不同層級&#xff0c;而import語句的導入行為與它們密切相關。以下是詳細對比和解釋&#xff1a; &#x1f4e6; 1. 核心概…

裸機上的 printf:在無操作系統環境下構建 C 標準庫

在嵌入式開發和底層系統編程領域&#xff0c;裸機開發是一項極具挑戰性但又至關重要的任務。想象一下&#xff0c;在沒有操作系統支持的情況下&#xff0c;讓 C 語言的標準庫函數&#xff0c;如printf正常工作&#xff0c;這聽起來是不是很有趣又充滿挑戰&#xff1f;今天&…

基于STM32F103的智能機械臂識別與控制項目(課件PPT+源代碼)

以下是基于 STM32F103 的智能機械臂識別與控制項目的詳細介紹&#xff1a; 項目概述 該項目以 STM32F103 為核心控制器&#xff0c;結合多種傳感器和技術&#xff0c;實現了機械臂的智能識別與控制功能&#xff0c;可完成倉庫貨物的識別、搬運等任務&#xff0c;并支持多種控…

Codeforces Round 1023 (Div. 2)

Dashboard - Codeforces Round 1023 (Div. 2) - Codeforces 一個構造問題&#xff0c;我把最大的數放在一個數組&#xff0c;其余數放在另一個數組&#xff0c;就能保證gcd不同 來看代碼&#xff1a; #include <bits/stdc.h> using namespace std;int main() {int t;ci…

6.01 Python中打開usb相機并進行顯示

本案例介紹如何打開USB相機并每隔100ms進行刷新的代碼,效果如下: 一、主要思路: 1. 打開視頻流、讀取幀 self.cam_cap = cv2.VideoCapture(0) #打開 視頻流 cam_ret, cam_frame = self.cam_cap.read() //讀取幀。 2.使用定時器,每隔100ms讀取幀 3.顯示到Qt的QLabel…

JVM——即時編譯

分層編譯模式&#xff1a;動態平衡啟動速度與執行效率 分層編譯是現代JVM&#xff08;如HotSpot、GraalVM&#xff09;實現高性能的核心策略之一&#xff0c;其核心思想是根據代碼的執行熱度動態選擇不同的編譯層次&#xff0c;實現啟動速度與運行效率的最佳平衡。以HotSpot虛…

Auto DOP:讓并行執行實現智能調優 | OceanBase 實踐

隨著數據量的迅速增長&#xff0c;企業數據庫往往面臨著一個困局&#xff1a;復雜的分析查詢需要充分的資源來保證性能&#xff0c;但過多增加并行執行又會造成資源競爭&#xff0c;影響系統穩定性。傳統基于DBA人工干預的并行度調節機制&#xff0c;既低效又難以適應動態變化的…

【區塊鏈】Uniswap之滑點(Slippage)

一、滑點是什么&#xff1f; 滑點&#xff08;Slippage&#xff09;是指你下單預期價格和最終成交價格之間的差距。 在 DEX 中&#xff0c;你的交易會影響池子的價格&#xff08;AMM機制&#xff09;&#xff0c;所以&#xff1a; 下單越大&#xff0c;滑點越大&#xff1b;…

[前端]Javascript獲取元素寬度

元素寬度屬性對比示意圖 ---------------------------------- | 外邊距&#xff08;margin&#xff09; | -------------------------------- | | 邊框&#xff08;border&#xff09; | | | -------------------------- | | | …

數字人驅動/動畫方向最新頂會期刊論文收集整理 | AAAI 2025

會議官方論文列表&#xff1a;https://ojs.aaai.org/index.php/AAAI/issue/view/624 以下論文部分會開源代碼&#xff0c;若開源&#xff0c;會在論文原文的摘要下方給出鏈接。 語音驅動頭部動畫/其他 EchoMimic: Lifelike Audio-Driven Portrait Animations through Editabl…