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

C語言指針算術運算深度解析:類型決定步長

     編輯:關於C

指針運算核心規則

指針加減整數時,步長 = sizeof(指針指向的類型)。這是 C 語言指針運算與整數運算的本質區別。

實驗代碼

#include <stdio.h>
int main() {
    char str[] = {'a','b','c','d','e'};
    int *p = (int*)str;   // 強制轉換演示,實際應保持類型一致
    char *q = str;
    
    printf("str 首地址: %p\n", (void*)str);  // 例: 0x7ffee4b8
    printf("q 初始: %p\n", (void*)q);        // 0x7ffee4b8
    printf("p 初始: %p\n", (void*)p);        // 0x7ffee4b8
    
    q++;  // char* +1 → 移動 1 字節
    p++;  // int* +1 → 移動 4 字節 (假設 32 位 int)
    
    printf("q++ 後: %p\n", (void*)q);       // 0x7ffee4b9
    printf("p++ 後: %p\n", (void*)p);       // 0x7ffee4bc
    
    // 遍歷演示
    q = str;
    for (int i = 0; i < 5; i++) printf("%c ", *q++);  // 正確遍歷 char 數組
    return 0;
}

輸出結果解析

str 首地址: 0x7ffee4b8
q 初始: 0x7ffee4b8
p 初始: 0x7ffee4b8
q++ 後: 0x7ffee4b9  (+1 byte)
p++ 後: 0x7ffee4bc  (+4 bytes)
遍歷輸出: a b c d e

指針運算數學定義

設指針 ptr 指向類型 T,sizeof(T) = S:

  • ptr + n → 地址增加 n * S 字節,結果類型仍為 T*
  • ptr - n → 地址減少 n * S 字節
  • ptr2 - ptr1 (同類型指針) → 返回元素個數差 (addr2 - addr1) / S,類型 ptrdiff_t

類型不匹配的後果

int arr[5] = {1,2,3,4,5};
char *cp = (char*)arr;  // 強制轉換
printf("%d\n", *cp);    // 只讀取 arr[0] 低 8 位 (小端機: 1)
cp += 4;                // 移動 4 字節 → 指向 arr[1]
printf("%d\n", *(int*)cp); // 讀取 arr[1] 完整 4 字節: 2

教訓: 指針類型必須與數據實際類型匹配,否則解引用會讀錯數據、對齊錯誤甚至未定義行為。

數組遍歷三種等價方式

char str[] = "hello";
int len = sizeof(str) - 1;  // 排除 '\0'

// 1. 下標法
for (int i = 0; i < len; i++) putchar(str[i]);

// 2. 數組名+偏移
for (int i = 0; i < len; i++) putchar(*(str + i));

// 3. 指針遍歷 (最高效,最地道)
for (char *p = str; *p; p++) putchar(*p);  // 利用 '\0' 結束

進階:指針差值應用

char *str = "hello world";
char *p = strchr(str, 'w');  // 找到 'w'
size_t offset = p - str;     // 計算偏移量 = 6
printf("'w' at index %zu\n", offset);

避坑指南

錯誤代碼問題正確寫法
int *p; p += 100;未初始化指針運算 → UB先指向有效數組/內存
p = arr + 10; (arr 長度 5)指向數組尾後一個元素合法,再往後非法確保 p 在 [arr, arr+len] 範圍
malloc(n); p += n;指向釋放後/越界內存記錄基址 base = p,釋放用 free(base)
printf("%d", p);指針用 %d 打印截斷/未定義printf("%p", (void*)p);

總結

指針運算不是整數運算。步長由指向類型決定,邊界由分配對象決定。永遠保持指針類型與數據類型一致,並在有效範圍內操作。

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