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

C 語言指標進階測驗:三道經典題目驗證你的指標功力

     編輯:關於C

題目一:負索引存取


#include <stdio.h>
int main(void)
{
    char *p = NULL;
    char *tmp = "12345678";
    p = (char *)(tmp + 4);   // tmp 指向 '1',tmp+4 指向 '5'
    // p[-1] = ?   p[-5] = ?
    return 0;
}

解析

  • tmp 位址設為 base,內容 '1','2','3','4','5','6','7','8','\0'。
  • p = base + 4 → 指向 '5'(索引 4)。
  • p[-1] 等價 *(p - 1) = *(base + 3) = '4'。
  • p[-5] 等價 *(p - 5) = *(base - 1) → 未定義行為(越界存取字串常量前方記憶體)。

答案:p[-1] == '4';p[-5] 觸發 UB,可能崩潰或讀到垃圾值。

題目二:型別轉換與記憶體重疊


#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    char *data = "12345678";
    short *tmp = NULL;
    char p[6] = {0};

    tmp = (short *)&p[2];           // tmp 指向 p[2], p[3] (2 bytes)
    *tmp = atoi(&data[4]);          // data[4]='5',atoi("5678")=5678 = 0x162E

    // p[0]..p[5] = ?
    return 0;
}

解析

  • p 初始全 0:[0,0,0,0,0,0]。
  • tmp 指向 &p[2],寫入 short 值 5678 (0x162E)。
  • 假設小端序(x86/ARM 常見):
    • p[2] = 低位元組 0x2E (46) → ASCII '.'
    • p[3] = 高位元組 0x16 (22) → 控制字元
  • 大端序則相反:p[2]=0x16, p[3]=0x2E。
  • p[0], p[1], p[4], p[5] 保持 0。

答案(小端序):p = {0, 0, 46, 22, 0, 0}(以數值顯示)。

題目三:任意位址解參考


int *p = (int *)0x1234;
printf("p = %p, *p = %d\n", p, *p);

解析

  • p 值為 0x1234,列印無問題。
  • *p 嘗試讀取實體/虛擬位址 0x1234 的 4 位元組。
  • 用戶態程式無權存取該位址 → 作業系統送出 SIGSEGV (Segmentation fault),程式終止。
  • 嵌入式無 MMU 環境或核心模組中可能合法,但標準用戶態 C 程式**絕對非法**。

答案:程式崩潰(Segmentation fault),無法正常輸出。

核心知識點總結

  1. 指標算術:p[i] ≡ *(p+i),負索引合法前提是結果位址在同一合法物件範圍內。
  2. 型別懲罰/別名規則:透過 short* 存取 char[] 違反 Strict Aliasing Rule,行為未定義(雖多數編譯器在低優化下按預期工作)。
  3. 端序影響:多位元組型別在記憶體中位元組序與 CPU 架構相關。
  4. 位址空間隔離:用戶態無法隨意解參考任意數值位址,需 mmap、ioremap 等機制映射。

避坑建議

  • 嚴禁對字串常量指標做負索引越界存取。
  • 型別轉換指標時使用 union 或 memcpy 避免 Strict Aliasing 違規。
  • 嵌入式開發確認目標平台端序,編寫可移植程式碼。
  • 永遠檢查指標有效性再解參考(NULL、對齊、映射範圍)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved