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

C語言字符串存儲深度解析:棧、堆、數據段與文本段的區別

     編輯:關於C語言

重讀《C專家編程》總能帶來新收穫,這正是「溫故而知新」的樂趣。最近研讀程序內存佈局與數組指針差異時,發現自己對C字符串的理解原本還存在模糊地帶,技術進步果然需要點滴積累。

可執行程序的段結構

可執行文件在內存中主要分為以下段:

  • 文本段:存放程式碼、字符串常量、只讀數據
  • 數據段:存放已初始化的全局/靜態變量
  • BSS段:存放未初始化的全局/靜態變量(運行時清零)
  • 棧區:函數調用、局部變量、參數傳遞

內存段結構圖

實測代碼驗證字符串存儲位置

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char* p = "we are in text segment";      // 指針在數據段,字符串在文本段
char globalArr[] = "ds";                  // 數組在數據段
int globalInt = 6;                        // 數據段
int globalIntBSS;                         // BSS段
double globalDoubleBSS;                   // BSS段
char globalArrBSS[10];                    // BSS段

int main(void) {
    char arr[] = "we are in stack!";      // 棧區
    
    puts("\n=== 棧區地址 ===");
    printf("%p\n", arr);
    printf("%p\n", &arr[1]);
    printf("%p\n", &arr[2]);
    
    puts("\n=== BSS段地址 ===");
    printf("%p\n", &globalIntBSS);
    printf("%p\n", &globalDoubleBSS);
    strcpy(globalArrBSS, "lalala");
    printf("%s\n", globalArrBSS);
    printf("%zu\n", sizeof(globalArrBSS));
    printf("%p\n", globalArrBSS);
    printf("%p\n", &globalArrBSS[1]);
    
    puts("\n=== 數據段地址 ===");
    printf("%p\n", &p);           // 指針變量本身的地址
    printf("%p\n", globalArr);    // 數組首地址
    printf("%p\n", &globalArr[1]);
    printf("%p\n", &globalArr[2]);
    printf("%p\n", &globalInt);
    
    puts("\n=== 文本段地址 ===");
    printf("%p\n", p);            // 字符串常量地址
    printf("%p\n", &p[1]);
    
    return 0;
}

程序運行結果

從輸出可見,各段地址差異明顯,驗證了內存佈局理論。

四種字符串存儲場景詳細解析

一、字符串在棧區

char arr[] = "we are in stack!"; 定義的字符數組存放在棧上。arr 標記了字符串首地址,因為是棧上變量,可讀可寫,修改 arr[1] = 'd'; 完全合法。

二、字符串在BSS段

BSS段在目標文件中僅記錄未初始化變量的大小,不佔用文件空間。程序運行時由加載器分配並清零。
double globalDoubleBSS; 和 char globalArrBSS[10]; 均未初始化,故屬於BSS段。運行時用 strcpy() 賦值後可正常讀寫。

三、字符串在數據段

這裡有個關鍵區別:

  • char* p = "..."; —— 指針 p 在數據段(已初始化),但它指向的字符串常量在文本段(只讀)
  • char globalArr[] = "ds"; —— 數組本身在數據段,內容可修改

因此 globalArr[1] = 'a'; 合法,但 p[1] = 'a'; 會導致段錯誤。

四、字符串在文本段

char* p = "we are in text segment"; 中的字符串字面量存放在文本段,屬於只讀內存。嘗試修改會觸發 Segmentation Fault:

段錯誤演示


核心結論:char* p 與 char p[] 的本質區別在於——前者是指向只讀常量的指針,後者是可修改的字符數組。這正是《C專家編程》反覆強調的「數組與指針並不相同」的核心觀點之一。

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