首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C語言指針完整指南:從基礎定義到進階應用

     編輯:關於C語言

C語言指針完整指南:從基礎定義到進階應用

指針是C語言的核心特性之一,也是許多初學者感到棘手的概念。本文將系統講解指針的定義、操作、與數組/字符串的關係,以及實際編程中的常見應用場景。

一、指針變量的定義與基本操作

指針變量的本質是存儲內存地址的變量。其定義語法為:

數據類型 *指針變量名;

例如 int *p; 表示定義一個指向 int 類型數據的指針變量 p。指針的核心作用只有一個:根據地址值訪問對應的存儲空間。

基本示例

#include <stdio.h>
int main() {
    int *p;       // 定義指針變量 p,只能指向 int 類型數據
    int a = 90;
    p = &a;       // p 指向變量 a 的地址
    
    *p = 10;      // 解引用:訪問 p 指向的存儲空間,修改 a 的值為 10
    a = 20;       // 直接修改 a
    printf("%d\n", *p); // 輸出 20
    return 0;
}

關鍵點:定義時的 * 是聲明標識,使用時的 * 是解引用操作符,兩者含義不同。

二、指針的類型與大小

雖然所有指針在 64 位系統中均佔用 8 字節,但指針必須區分類型:

#include <stdio.h>
int main() {
    char *cp; int *ap; long *bp;
    printf("cp=%zd, ap=%zd, bp=%zd\n", sizeof(cp), sizeof(ap), sizeof(bp));
    // 輸出均為 8(64位編譯器)
    // 為什麼要分類型?因為編譯器需要知道解引用時從內存讀取多少字節。
    return 0;
}

三、指針作為函數參數:實現多返回值與外部變量修改

1. 在函數內修改外部變量

#include <stdio.h>
void change(int *p);
int main() {
    int a = 10;
    change(&a); // 傳遞 a 的地址
    printf("a=%d\n", a); // 輸出 20
    return 0;
}
void change(int *p) {
    *p = 20; // 通過指針修改外部變量
}

2. 讓函數間接擁有多個返回值

#include <stdio.h>
void test(int a, int b, int *c, int *d);
int main() {
    int a = 15, b = 10, he = 0, cha = 0;
    test(a, b, &he, &cha);
    printf("和是%d,差是%d", he, cha); // 輸出:和是25,差是5
    return 0;
}
void test(int a, int b, int *c, int *d) {
    *c = a + b;
    *d = a - b;
}

四、指針與數組的深度關聯

數組名在大多數上下文中轉換為指向首元素的指針。指針算術運算會根據指針類型自動調整步長。

訪問數組元素的三種等價方式

int ages[5] = {10, 11, 19, 78, 67};
int *p = ages; // p 指向首元素

// 1. 數組下標
ages[2];        // 19
// 2. 指針下標
p[2];           // 19
// 3. 指針算術 + 解引用
*(p + 2);       // 19

指針步長由類型決定

int *ip;   // ip+1 增加 4 字節
char *cp;  // cp+1 增加 1 字節
double *dp; // dp+1 增加 8 字節

實戰:在函數中接收數組

void change(int *array) { // 等價於 int array[]
    printf("%d\n", array[2]); // 訪問第三個元素
}

int main() {
    int ages[5] = {10, 11, 19, 78, 67};
    change(ages); // 傳遞首元素地址
    return 0;
}

五、指針與字符串:兩種定義方式的本質區別

定義方式代碼示例存儲區域可修改性適用場景
字符數組char name[] = "itcast";棧區內容可修改字符串需頻繁修改
字符指針char *name = "itcast";常量區內容不可修改(嘗試修改會崩潰)字符串只讀、頻繁使用、共享常量池

字符指針的常量特性演示

char *name2 = "it";
char *name3 = "it";
// *name2 = 'T'; // 錯誤!程序崩潰,因為指向常量區
printf("%p\n%p\n", name2, name3); // 地址相同,編譯器優化共享常量

字符串輸入示例

int main() {
    char name[20];
    printf("請輸入姓名:\n");
    scanf("%s", name); // 讀取直到空白字符,自動添加 '\0'
    return 0;
}

六、指針數組與二維字符數組:構建字符串集合

void test2() {
    // 指針數組(字符串數組):每個元素是指針,指向常量區字符串
    char *names[5] = {"jack", "rose", "jake"};
    
    // 二維字符數組(字符串數組):每個元素是固定大小的字符數組,存儲在棧區
    char names2[2][10] = {"jack", "rose"};
}

七、總結與最佳實踐

  • 指針類型必須與目標數據類型匹配,否則解引用會讀取錯誤字節數。
  • 函數參數使用指針可實現「傳址調用」,修改外部變量或返回多個值。
  • 數組名退化為指針時失去長度信息,傳遞數組給函數時建議同步傳遞長度。
  • 字符串字面量存儲在只讀內存區,切勿通過指針修改;需修改時請使用字符數組。
  • 指針算術自動按類型大小縮放,p + i 等價於 &p[i]。

掌握指針是精通 C 語言的關鍵門檻,建議多動手實驗內存地址變化,結合調試器觀察堆棧分佈,將抽象概念具象化。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved