C指針那點事兒

来源:http://www.cnblogs.com/jiahao89/archive/2016/11/24/6100035.html
-Advertisement-
Play Games

指針: 用來存放變數地址的變數,就成為"指針變數". 定義: 一般形式:類名標識符 指針變數名; " "是說明符,用來說明這個變數是個指針變數,是不能省略的,但不屬於變數名的一部分 前面的類型標誌符表示指針變數所只想的變數的類型,而且只能指向這種類型的變數 示例1:值交換 示例2:函數多個返回值 示 ...


  • 指針: 用來存放變數地址的變數,就成為"指針變數".
  • 定義: 一般形式:類名標識符 *指針變數名;

    int *p;
    float *q;
  • "*"是說明符,用來說明這個變數是個指針變數,是不能省略的,但不屬於變數名的一部分
  • 前面的類型標誌符表示指針變數所只想的變數的類型,而且只能指向這種類型的變數

示例1:值交換

```c
void swap(char v1, char v2) {
// 中間變數
char temp;

// 取出v1指向的變數的值
temp = *v1;

// 取出v2指向的變數的值,然後賦值給v1指向的變數
*v1 = *v2;

// 賦值給v2指向的變數
*v2 = temp;

}
int main()
{
char a = 10, b = 9;
printf("更換前:a=%d, b=%d\n", a, b);

swap(&a, &b);

printf("更換後:a=%d, b=%d", a, b);
return 0;

}
```

示例2:函數多個返回值

```c

// 計算2個整型的和與差
int sumAndMinus(int v1, int v2, int minus) {
// 計算差,並賦值給指針指向的變數
minus = v1 - v2;

// 計算和,並返回和
return v1 + v2;

}
int main()
{
// 定義2個int型變數
int a = 6, b = 2;

// 定義2個變數來分別接收和與差
int sum, minus;

// 調用函數
sum = sumAndMinus(a, b, &minus);

// 列印和
printf("%d+%d=%d\n", a, b, sum);

// 列印差
printf("%d-%d=%d\n", a, b, minus);
return 0;

}

```

示例3:用指針遍歷字元串

// 定義一個指針p
char *p;

// 定義一個數組s存放字元串
char s[] = "mj";

// 指針p指向字元串的首字元'm'
p = s; // 或者 p = &s[0];

for (; *p != '\0'; p++) {
    printf("%c \n", *p);
}

指針也是C語言中的一種數據類型,因此一個函數的返回值肯定可以是指針類型的。
返回指針的函數的一般形式為:類型名 * 函數名(參數列表)

示例4:比如下麵這個函數,返回一個指向char類型變數的指針

```c
// 將字元串str中的小寫字母變成大寫字母,並返回改變後的字元串
// 註意的是:這裡的參數要傳字元串變數,不能傳字元串常量
char * upper(char str) {
// 先保留最初的地址。因為等會str指向的位置會變來變去的。
char
dest = str;

// 如果還不是空字元
while (*str != '\0') {
    // 如果是小寫字母
    if (*str >= 'a' && *str <= 'z') {
        // 變為大寫字母。小寫和大寫字母的ASCII值有個固定的差值
        *str -= 'a' - 'A';
    }
    
    // 遍歷下一個字元
    str++;
}

// 返回字元串
return dest;

}
```

指向函數的指針函數作為一段程式,在記憶體中也要占據部分存儲空間,它也有一個起始地址,即函數的入口地址。函數有自己的地址,那就好辦了,我們的指針變數就是用來存儲地址的。因此,可以利用一個指針指向一個函數。其中,函數名就代表著函數的地址。
定義的一般形式:函數的返回值類型 (*指針變數名)(形式參數1, 形式參數2, ...);

#include <stdio.h>

int sum(int a, int b) {
    return a + b;
}

int main()
{
    // 定義一個指針變數p,指向sum函數
    int (*p)(int a, int b) = sum;
    // 或者 int (*p)(int, int) = sum;
    // 或者 int (*p)() = sum;
    
    // 利用指針變數p調用函數
    int result = (*p)(1, 3);
    // 或者 int result = p(1, 3);
    
    printf("%d", result);
    return 0;
}

指向指針的函數註意

1> 由於這類指針變數存儲的是一個函數的入口地址,所以對它們作加減運算(比如p++)是無意義的。難道p++就會指向下一個函數了?可笑至極!!沒這回事。

2> 返回指針的函數的定義char upper(char str) 和 指向函數的指針的定義int ( *p)(int a, int b)非常相似,使用時特別註意區分

3> 指向函數的指針變數主要有兩個用途:

調用函數

將函數作為參數在函數間傳遞。我這麼一說,可能還不是很明白,舉個例子。

#include <stdio.h>

// 減法運算
int minus(int a, int b) {
    return a - b;
}

// 加法運算
int sum(int a, int b) {
    return a + b;
}

// 這個counting函數是用來做a和b之間的計算,至於做加法還是減法運算,由函數的第1個參數決定
void counting( int (*p)(int, int) , int a, int b) {
    int result = p(a, b);
    printf("計算結果為:%d\n", result);
}

int main()
{
    // 進行加法運算
    counting(sum, 6, 4);
    
    // 進行減法運算
    counting(minus, 6, 4);
    
    return 0;
}
  • 每個結構體變數都有自己的存儲空間和地址,因此指針也可以指向結構體變數

  • 結構體指針變數的定義形式:struct 結構體名稱 *指針變數名

  • 有了指向結構體的指針,那麼就有3種訪問結構體成員的方式

結構體變數名.成員名
(*指針變數名).成員名
指針變數名->成員名

#include <stdio.h>

int main(int argc, const char * argv[]) {
    // 定義一個結構體類型
    struct Student {
        char *name;
        int age;
    };
    
    // 定義一個結構體變數
    struct Student stu = {"MJ", 27};
    
    // 定義一個指向結構體的指針變數
    struct Student *p;
    
    // 指向結構體變數stu
    p = &stu;

    /*
     這時候可以用3種方式訪問結構體的成員
     */
    // 方式1:結構體變數名.成員名
    printf("name=%s, age = %d \n", stu.name, stu.age);
    
    // 方式2:(*指針變數名).成員名
    printf("name=%s, age = %d \n", (*p).name, (*p).age);
    
    // 方式3:指針變數名->成員名
    printf("name=%s, age = %d \n", p->name, p->age);
    
    return 0;
}

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 完善了下 文件中的文件及文件夾中的複製!如果有更優解決方案請不吝指教 protected void FileDepthCopy(string source, string target) { if (Directory.Exists(source))//判斷源文件是否存在 { if (!Direct ...
  • 常用的一些開源組件整理: 導出Excel報表的插件:NOPI.dll(基於微軟OpenXml實現)開源的作業調度和自動任務框架:Quartz.NET用於大數據搜索引擎的全文檢索框架:Lucene.net微軟針對企業級應用開發的最佳實踐組件:Enterprise Library 5.0國外一個牛人寫的 ...
  • MVVM是一個比較熱門的開發框架,儘管已經出現很久了,仍然比較受歡迎。MVVM框架包括: M:Model;Model指的是數據模型,例如你要在頁面展示聯繫人信息,那麼Model就是聯繫人的模型,包括聯繫人的名字,電話號碼,頭像等。。。 V:View;View指的是展示的頁面,比如你所現在看到的這篇文 ...
  • 在項目開發過程中,有時會需要用到調用第三方程式實現本系統的某一些功能,例如本文中需要使用到的swftools插件,那麼如何在程式中使用這個插件,並且該插件是如何將PDF文件轉化為SWF文件的呢?接下來就會做一個簡單的介紹。 在.NET平臺中,對C#提供了一個操作對本地和遠程的訪問進程,使能夠啟動和停 ...
  • 本次活動,只是一個嘗試,也許效果好,也許效果差,但不嘗試一下,又怎麼知道呢~~~~最後謝謝大伙的支持! ...
  • 1、類圖 2、創建項目 ………………………… 3、 VisualComponent:抽象界面構件類,充當抽象構件類 為了突出與模式相關的核心代碼,咋基本實例中對空間代碼進行了簡化。 namespace DecoratorSample { /// <summary> /// 抽象構件類 /// </s ...
  • Hibernate中的三種狀態 瞬時狀態:剛創建的對象還沒有被Session持久化、緩存中不存在這個對象的數據並且資料庫中沒有這個對象對應的數據為瞬時狀態這個時候是沒有OID。 持久狀態:對象經過Session持久化操作,緩存中存在這個對象的數據為持久狀態並且資料庫中存在這個對象對應的數據為持久狀態 ...
  • 運行結果: ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...