C語言-指針用法概述

?目錄

1.指針基礎概念??

2.?指針與數組

3. 指針作為函數參數

4. 動態內存分配

?5. 指針的高級用法

6. 常見錯誤與注意事項

7. 指針數組 vs. 數組指針?????

8.總結與建議


????????本文主要作為指針用法的復習,會對指針的大致用法進行舉例和概述。


1.指針基礎概念??

  • ?什么是指針?:指針是一種變量,它存儲的是另一個變量的內存地址,而不是數據本身。這允許你通過地址間接訪問和操作數據
  • ?聲明指針?:聲明指針時,需要在數據類型后跟一個星號 *。例如 int *p;聲明了一個指向整型的指針 p
  • ?取地址與解引用?:
    • 使用取地址運算符 &可以獲取變量的地址。例如,int a = 10; int *p = &a;使得指針 p指向變量 a的地址
    • 使用解引用運算符 *可以訪問指針所指向地址中存儲的值。例如,printf("%d", *p);會輸出 a的值 10

2.?指針與數組

????????C語言中數組名通常可被當作指向其首元素的指針使用。

int arr[3] = {1, 2, 3};
int *p = arr; // p 指向 arr[0]
printf("%d", *(p + 1)); // 輸出 arr[1] 的值 2

????????指針可以通過算術運算(如 +-++--)來遍歷數組,單位是所指向類型的大小(例如 int指針每次移動通常為4字節)。


3. 指針作為函數參數

????????通過向函數傳遞指針(即變量的地址),可以在函數內部修改調用函數中的變量值,實現“引用傳遞”。

void swap(int *a, int *b) {int temp = *a;*a = *b;*b = temp;
}int main() {int x = 1, y = 2;swap(&x, &y); // 交換后 x=2, y=1
}

????????當需要向函數傳遞數組時,通常傳遞數組名(即首元素地址)和數組長度。使用 const限定符可以保護指針所指向的數據在函數內不被修改。


4. 動態內存分配

????????C語言允許在程序運行時動態地申請和釋放內存,這類內存分配在上進行。

  • ?malloc?:分配指定字節數的內存,?不初始化內存內容,返回 void*
int *p = (int*)malloc(5 * sizeof(int)); // 分配容納5個整數的空間
if (p == NULL) { /* 處理分配失敗 */ }
  • calloc?:分配指定數量、特定類型的內存空間,并初始化為0?。
int *p = (int*)calloc(5, sizeof(int)); // 分配并初始化5個整數為0
  • realloc?:調整之前通過 malloc, callocrealloc分配的內存塊的大小。
  • free?:?必須用于釋放之前動態分配的內存,否則會導致內存泄漏。釋放后最好將指針置為 NULL,以避免“懸空指針”。
    free(p);
    p = NULL;

?5. 指針的高級用法

  • 多級指針?:指向指針的指針,例如 int **pp是指向 int*的指針,常用于動態二維數組或需要修改指針本身值的場景。

  • 函數指針?:指向函數的指針,允許動態調用函數,常用于回調機制。
int add(int a, int b) { return a + b; }
int (*funcPtr)(int, int) = add; // 聲明并初始化函數指針
printf("%d", funcPtr(2, 3)); // 通過指針調用函數,輸出5

??const與指針?:

  • const int *pint const *p:指向常量數據的指針,?不能通過 p修改所指數據,但可以改變 p的指向。
  • int *const p:指針本身是常量,?p的指向不能變,但可以通過 p修改所指數據。
  • const int *const p:指針本身和所指數據都不可變。

6. 常見錯誤與注意事項

  • 未初始化的指針(野指針)??:聲明指針后未賦予有效地址前就使用,可能導致程序崩潰。?務必初始化,例如設為 NULL
  • 懸空指針?:指針指向的內存已被釋放,但指針仍在被使用。?釋放內存后應將指針置為 NULL?
  • 內存泄漏?:分配的內存未被釋放且失去對其的引用,導致內存浪費。確保 ?malloc/callocfree成對出現?
  • ?越界訪問?:訪問了分配內存范圍之外的空間,行為不可預知。?確保訪問在合法范圍內?

7. 指針數組 vs. 數組指針?????

對于我們新手來說特別難搞清楚他們的區別,理解它們的區別很重要:

類型

聲明示例

含義

?指針數組?

int *arr[10]

一個數組,其每個元素都是指向 int的指針

?數組指針?

int (*arr)[10]

一個指針,它指向一個包含10個整數的數組

理解指針數組(Array of Pointers)和數組指針(Pointer to Array)的區別確實是C語言學習中的一個重點和難點。下面我將通過一個表格幫你快速梳理它們的核心差異,然后進行詳細解釋。

特性

指針數組 (Array of Pointers)

數組指針 (Pointer to Array)

?本質?

數組,其每個元素都是指針?

指針,它指向整個數組?

?聲明語法?

數據類型 *數組名[數組長度];
(例如:int *ptr_arr[5];

數據類型 (*指針名)[數組長度];
(例如:int (*arr_ptr)[5];

?內存布局?

連續存儲多個指針(每個指針占4或8字節)

存儲一個指針變量(指向數組首地址),本身通常占4或8字節

?步長?

指針運算以單個指針的大小為單位(如+1移動4或8字節)

指針運算以整個數組的大小為單位(如+1移動sizeof(類型[長度])字節)

?典型用途?

管理多個字符串、存儲動態分配的不同長度內存塊的地址、命令行參數argv

操作多維數組(尤其是二維數組)、向函數傳遞固定長度的數組

深入理解兩者

1. 指針數組(Array of Pointers)

指針數組的本質是一個數組,但這個數組里的每個元素都不是普通的數據,而是一個指針變量,這些指針可以指向相同或不同類型的地址。

  • ?聲明與初始化?

    語法格式為:數據類型 *數組名[數組長度];

    #include <stdio.h>int main() {int a = 10, b = 20, c = 30;// 聲明并初始化一個指針數組,元素是int指針int *ptr_arr[3] = {&a, &b, &c}; // 遍歷指針數組,通過解引用訪問所指的值for (int i = 0; i < 3; i++) {printf("ptr_arr[%d] = %d\n", i, *ptr_arr[i]);}return 0;
    }

    輸出:

    ptr_arr[0] = 10
    ptr_arr[1] = 20
    ptr_arr[2] = 30
  • ?常見應用場景?

    • ?管理多個字符串?:這是指針數組非常常見的用途,可以高效地處理一堆長度不一的字符串。

      char *str_arr[] = {"Hello", "World", "C", "Programming"}; // 初始化字符串指針數組
      for (int i = 0; i < 4; i++) {printf("%s ", str_arr[i]);
      }
      // 輸出: Hello World C Programming
    • ?動態內存管理?:當需要動態分配多個獨立的內存塊時,可以用指針數組來存儲這些內存塊的地址。

    • ?命令行參數?:C語言中的main函數參數char *argv[]就是一個典型的指針數組,用于存儲命令行輸入的字符串參數。

2. 數組指針(Pointer to Array)

數組指針的本質是一個指針,但它不是指向單個變量,而是指向整個數組

  • ?聲明與初始化?

    語法格式為:數據類型 (*指針名)[數組長度];?注意括號是必須的,它保證了*先與指針名結合。

    #include <stdio.h>int main() {int arr[5] = {1, 2, 3, 4, 5};// 聲明一個數組指針,指向包含5個int的數組int (*arr_ptr)[5] = &arr; // 取數組的地址賦給數組指針// 通過數組指針訪問數組元素for (int i = 0; i < 5; i++) {printf("%d ", (*arr_ptr)[i]); // 先解引用arr_ptr得到數組,再通過下標訪問}return 0;
    }

    輸出:

    1 2 3 4 5
  • ?常見應用場景?

    • ?處理二維數組?:數組指針在遍歷和理解二維數組時特別有用,它可以表示二維數組中的一行。

      int matrix[2][3] = {{1, 2, 3}, {4, 5, 6}};
      // 數組指針,指向一個包含3個int的數組(即一行)
      int (*row_ptr)[3] = matrix; // matrix是首行地址,可直接賦值for (int i = 0; i < 2; i++) {for (int j = 0; j < 3; j++) {printf("%d ", row_ptr[i][j]); // 像二維數組一樣訪問// 等價于 *(*(row_ptr + i) + j)}printf("\n");
      }

      輸出:

      1 2 3 
      4 5 6
    • ?向函數傳遞二維數組?:當函數需要接收一個二維數組時,使用數組指針可以明確列數。

?如何快速區分聲明?

記住一點:??“看括號和優先級”?

  • int *p[5];[]的優先級高于*,所以p先與[5]結合,說明p是一個數組,里面存放的是int*類型。這是指針數組

  • int (*p)[5];:括號()改變了優先級,*先與p結合,說明p是一個指針,它指向一個int [5]類型的數組。這是數組指針

注意事項

  1. ?匹配類型和長度?:對于數組指針,其指向的數組類型和長度必須嚴格匹配。例如,int (*p)[5]只能指向包含5個整數的數組。

  2. ?初始化?:使用指針數組時,務必確保其中的每個指針都指向有效的內存地址,避免野指針。

  3. ?內存管理?:如果指針數組的元素指向動態分配的內存,記得在使用完畢后釋放這些內存,防止內存泄漏。

?小總結

簡單來說:

  • ?指針數組?:是一個倉庫(數組)?,里面放著很多把鑰匙(指針)?,每把鑰匙可以打開不同的房間。

  • ?數組指針?:是一把特殊的鑰匙(指針)?,這把鑰匙對應著一整排連續的倉庫(整個數組)?

希望這些解釋和例子能幫助你清晰地區分指針數組和數組指針。


8.總結與建議

????????指針是C語言的精髓,提供了直接操作內存的強大能力和靈活性,常用于動態內存管理、數組操作、函數參數傳遞以及構建復雜數據結構(如鏈表、樹)。同時,指針的使用也伴隨著風險,需要謹慎處理內存管理和避免常見陷阱。

?最佳實踐?:

  • ?始終初始化指針,若暫時不知指向何處,可初始化為 NULL
  • ?檢查動態內存分配?(如 malloc, calloc)的返回值是否為 NULL,以防分配失敗。
  • 確保分配的內存及時釋放,并在釋放后將指針置為 NULL?。
  • ?使用 const限定符保護不應被修改的數據,增強代碼健壯性。
  • 利用工具?(如 Valgrind)檢查內存泄漏和非法訪問。

希望以上梳理能幫助你更好地理解C語言中的指針。

請大家點點關注和點贊,后面我一定會分享更多實用的文章的

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

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

相關文章

Java調用Whisper和Vosk語音識別(ASR)模型,實現高效實時語音識別(附源碼)

簡介 語音識別&#xff08;Automatic Speech Recognition, ASR&#xff09;是將人類的語音信號自動轉換為對應文字的技術&#xff0c;它使計算機能夠“聽懂”人說的話&#xff0c;是人機語音交互的核心技術&#xff0c;廣泛應用于智能助手、語音輸入、客服系統等場景。 現在我…

第3周 機器學習課堂記錄

1.學習問題的分類有監督的學習分類回歸無監督學習聚類密度估計&#xff1a;確定輸入空間中的數據的分布可視化&#xff1a;把高位空間中的數據投影到二維或三維空間強化學習不給定最優輸出的示例&#xff0c;而是通過試錯發現最優輸出2.泛化versus過度擬合背景引入&#xff1a;…

消息隊列(MQ)高級特性深度剖析:詳解RabbitMQ與Kafka

一、引言&#xff1a;為什么需要關注高級特性&#xff1f; 在現代分布式系統架構中&#xff0c;消息隊列&#xff08;Message Queue&#xff09;已成為不可或缺的核心組件。初級使用消息隊列可能只需幾行代碼就能實現基本功能&#xff0c;但要真正發揮其在大規模生產環境中的威…

【GPT入門】第65課 vllm指定其他卡運行的方法,解決單卡CUDA不足的問題

【GPT入門】第65課 vllm指定其他卡運行的方法&#xff0c;解決單卡CUDA不足的問題&#xff11;.原理說明&#xff1a;&#xff12;.實踐&#xff11;.原理 要將 vllm 部署在第二張 GPU 卡上&#xff08;設備編號為 1&#xff09;&#xff0c;只需在命令前添加 CUDA_VISIBLE_DE…

Spring Boot Actuator自定義指標與監控實踐指南

Spring Boot Actuator自定義指標與監控實踐指南 本篇文章以生產環境實戰經驗為主線&#xff0c;結合某電商系統的業務場景&#xff0c;講解如何在Spring Boot Actuator中添加并暴露自定義指標&#xff0c;并使用Prometheus和Grafana進行完整的監控與告警配置。 一、業務場景描述…

Vue報錯<template v-for=“option in cardOptions“ :key=“option.value“>

在Vue項目中遇到報錯&#xff0c;原因是模板中使用了<template>標簽內的v-for指令&#xff0c;而當前Vue版本不支持此用法。解決方案是移除<template>標簽&#xff0c;直接在<el-option>上使用v-for。同時優化計算屬性cardOptions&#xff0c;使其能夠兼容歷…

人工智能學習:Transformer結構中的規范化層(層歸一化)

Transformer結構中的規范化層(層歸一化) 一、規范化層(層歸一化)介紹 概念 層歸一化(Layer Normalization) 是一種用于提高深度神經網絡訓練穩定性和加速收斂的技術,廣泛應用于現代深度學習模型中,尤其是在Transformer等序列建模網絡中。它通過對每一層的輸出進行歸一化…

盼之代售 最新版 decode__1174

聲明 本文章中所有內容僅供學習交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包內容、敏感網址、數據接口等均已做脫敏處理&#xff0c;嚴禁用于商業用途和非法用途&#xff0c;否則由此產生的一切后果均與作者無關&#xff01; 逆向分析 部分python代碼 cp1 execj…

Transformer系列 | Pytorch復現Transformer

&#x1f368; 本文為&#x1f517;365天深度學習訓練營中的學習記錄博客&#x1f356; 原作者&#xff1a;K同學啊 一、Transformer和Seq2Seq 在之前的博客中我們學習了Seq2Seq(深度學習系列 | Seq2Seq端到端翻譯模型)&#xff0c;知曉了Attention為RNN帶來的優點。那么有沒有…

【MySQL】常用SQL語句

介紹常用的DDL語句、DML語句基本語法分號結尾使用空格和縮進不區分大小寫--或#注釋單行內容 /*注釋多行內容*/DDL數據定義語句&#xff1a;定義數據庫、表、字段一、操作庫-- 創建庫create database db1;-- 創建庫是否存在&#xff0c;不存在則創建create database if not exi…

云手機就是虛擬機嗎?

云手機并非等同于虛擬機&#xff0c;盡管二者存在一定相似性&#xff0c;但有著諸多區別&#xff0c;以下從多個方面來分析&#xff1a;云手機是一種基于云計算技術&#xff0c;將云端服務器虛擬化為手機設備&#xff0c;用戶能通過網絡遠程操控的虛擬手機服務&#xff0c;它從…

準確--Nginx 1.28.0 安裝與配置流程

Nginx 1.28.0 安裝與配置流程 1. 下載與解壓 cd ~ wget http://nginx.org/download/nginx-1.28.0.tar.gz tar -zxvf nginx-1.28.0.tar.gz cd nginx-1.28.02. 配置編譯參數 ./configure \--prefix/home/ynnewweb/nginx \--with-http_ssl_module \--with-http_gzip_static_module…

無標記點動捕新范式:Xsens系統助力人形機器人實現毫米級動作復刻

Xsen搭載Manus數據手套在機器人操作與機器學習中的應用當前&#xff0c;人形機器人正加速向工業裝配、家庭陪護、倉儲物流等場景滲透&#xff0c;而 “如何讓機器人的動作既符合人類運動規律&#xff0c;又能實現高精度執行” 成為制約其落地的核心瓶頸。Xsens 高精度全身動捕系…

mysql57超管root忘記密碼怎么辦

目錄 背景 1.首先停止數據庫 2.使用免密模式啟動 3.修改密碼 3.1刷新權限配置 3.2修改密碼 4.殺掉mysql 5.重新正常啟動mysql 6.查看mysql狀態 7.驗證 7.1首先服務器本地驗證 7.2遠程驗證 背景 數據庫密碼忘記了,急的抓耳撓腮,怎么也想不起來,于是就開始重置吧 1.…

RESTful API:@RequestParam與@PathVariable實戰對比

RequestParam vs PathVariable 在刪除和查找操作中的使用差異 在項目實戰中&#xff0c;選擇使用 RequestParam 還是 PathVariable 來接收ID參數&#xff0c;通常基于以下幾個考慮因素&#xff1a; 1. RESTful API 設計原則 查找操作使用 PathVariable GetMapping("/depts…

劇本殺小程序系統開發:開啟沉浸式社交娛樂新紀元

在當今數字化浪潮席卷的時代&#xff0c;社交娛樂方式正經歷著前所未有的變革。劇本殺&#xff0c;這一融合了角色扮演、推理懸疑與社交互動的線下娛樂項目&#xff0c;近年來迅速風靡全國&#xff0c;成為年輕人熱衷的社交新寵。而隨著移動互聯網的蓬勃發展&#xff0c;劇本殺…

中線安防保護器,也叫終端電氣綜合治理保護設備為現代生活筑起安全防線

中線安防保護器&#xff08;Neutral Line Protection Device&#xff0c;簡稱NLPD&#xff09;是一種專門用于監測和保護電力系統中性線的安全裝置。中線安防保護器的基本原理為:通過電流檢測環節采集系統中性線上過電流信息&#xff0c; 經控制器快速計算并提取各次諧波電流的…

Spring Cloud Alibaba快速入門02-Nacos配置中心(下)

文章目錄前言配置中心 - 數據隔離示例1.先創建命名空間2.創建配置3.克隆配置4.動態切換環境5.yml多文檔模式spring.profiles.activedevspring.profiles.activetest總結前言 上一章簡單了解了Nacos配置中心的基本用法&#xff0c;這一章將開始Nacos配置中心的實戰案例。 配置中…

基于結構光相移法的三維重建

基于結構光相移法的三維重建程序 1. 介紹 結構光相移法是一種常用的三維重建技術&#xff0c;通過投射條紋圖案并捕捉其變形來計算物體的三維形狀。相移法通過多次投射不同相位的條紋圖案&#xff0c;利用相位信息來提取物體表面的深度信息。 2. MATLAB實現 2.1 生成條紋圖案 首…

機器學習10——降維與度量學習(K近鄰、多維縮放、主成分分析)

上一章&#xff1a;機器學習09——聚類 下一章&#xff1a;機器學習11——特征選擇與稀疏學習 機器學習實戰項目&#xff1a;【從 0 到 1 落地】機器學習實操項目目錄&#xff1a;覆蓋入門到進階&#xff0c;大學生就業 / 競賽必備 文章目錄一、k近鄰學習&#xff08;kNN&#…