kyle shanks
  • NEW!
    NEW!  Connect Ideas Across Notes
    Save time and share insights. With Paragraph Citation, you can quote others’ work with source info built in. If someone cites your note, you’ll see a card showing where it’s used—bringing notes closer together.
    Got it
      • Create new note
      • Create a note from template
        • Sharing URL Link copied
        • /edit
        • View mode
          • Edit mode
          • View mode
          • Book mode
          • Slide mode
          Edit mode View mode Book mode Slide mode
        • Customize slides
        • Note Permission
        • Read
          • Only me
          • Signed-in users
          • Everyone
          Only me Signed-in users Everyone
        • Write
          • Only me
          • Signed-in users
          • Everyone
          Only me Signed-in users Everyone
        • Engagement control Commenting, Suggest edit, Emoji Reply
      • Invite by email
        Invitee

        This note has no invitees

      • Publish Note

        Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

        Your note will be visible on your profile and discoverable by anyone.
        Your note is now live.
        This note is visible on your profile and discoverable online.
        Everyone on the web can find and read all notes of this public team.

        Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

        Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

        Explore these features while you wait
        Complete general settings
        Bookmark and like published notes
        Write a few more notes
        Complete general settings
        Write a few more notes
        See published notes
        Unpublish note
        Please check the box to agree to the Community Guidelines.
        View profile
      • Commenting
        Permission
        Disabled Forbidden Owners Signed-in users Everyone
      • Enable
      • Permission
        • Forbidden
        • Owners
        • Signed-in users
        • Everyone
      • Suggest edit
        Permission
        Disabled Forbidden Owners Signed-in users Everyone
      • Enable
      • Permission
        • Forbidden
        • Owners
        • Signed-in users
      • Emoji Reply
      • Enable
      • Versions and GitHub Sync
      • Note settings
      • Note Insights New
      • Engagement control
      • Make a copy
      • Transfer ownership
      • Delete this note
      • Save as template
      • Insert from template
      • Import from
        • Dropbox
        • Google Drive
        • Gist
        • Clipboard
      • Export to
        • Dropbox
        • Google Drive
        • Gist
      • Download
        • Markdown
        • HTML
        • Raw HTML
    Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
    Create Create new note Create a note from template
    Menu
    Options
    Engagement control Make a copy Transfer ownership Delete this note
    Import from
    Dropbox Google Drive Gist Clipboard
    Export to
    Dropbox Google Drive Gist
    Download
    Markdown HTML Raw HTML
    Back
    Sharing URL Link copied
    /edit
    View mode
    • Edit mode
    • View mode
    • Book mode
    • Slide mode
    Edit mode View mode Book mode Slide mode
    Customize slides
    Note Permission
    Read
    Only me
    • Only me
    • Signed-in users
    • Everyone
    Only me Signed-in users Everyone
    Write
    Only me
    • Only me
    • Signed-in users
    • Everyone
    Only me Signed-in users Everyone
    Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.

    Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Explore these features while you wait
    Complete general settings
    Bookmark and like published notes
    Write a few more notes
    Complete general settings
    Write a few more notes
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    --- title: '程式 & 記憶體 & 字串' disqus: kyleAlien --- 程式 & 記憶體 & 字串 === ## Overview of Content > 記憶體又稱為內存,以下會混用 :::success * 如果喜歡讀更好看一點的網頁版本,可以到我新做的網站 [**DevTech Ascendancy Hub**](https://devtechascendancy.com/) 本篇文章對應的是 [**C 語言記憶體區塊規劃 | Segment 段 | 字符串特性**](https://devtechascendancy.com/c-memory-segmentation-string-properties/) ::: [TOC] ## RAM 分配 - 概述 在 PC 作業系統中的軟體 (非 RTOS),因為有 **MMU (`Memory Manager Unit`) 硬體關係**,所以軟體實際取得的記憶體位置 **都是虛擬記憶體位置** 這樣的好處是可以 **更好的利用 規劃虛擬記憶體 空間** :::info 有關虛擬記憶體,可以參考 [**Linux 內存管理 & 操作**](https://hackmd.io/ptxTEwCzQBuxv61dGL_lvA?view) 這篇 ::: ### 程式記憶體管理方式/規劃區域 * 編譯器對程式編譯後,會將程式碼分析並區分為幾個區域:主要有分為 `棧`、`堆`、`數據區`、`常量區` 幾類,儲存區預如下表 > 每個區域都會有不同的特性 | 稱呼 | 記憶體區塊規劃名稱 | | -------- | -------- | | 棧 | `stack` | | 堆 | `heap` | | 數據區 | `.data`、`.bass` | | 常量區 | `.ro.data` | ### 函數使用: 棧 Stack * 在區域變數中使用,並有以下特點 1. **自動回收**:進入函數之前自動分配,離開函數時自動釋放 2. **反覆利用**:Stack 在 RAM 中的一個空間中,而該空間會不斷重複利用 3. **髒內存**:釋放的內存空間中的舊數據並不會配清除 4. **臨時性**:函數不能返回區域變數內的地址 (例如某一個指標),因為該空間在函數離開後自動釋放 ```c= #include <stdio.h> #include <stdlib.h> int *getTestValue() { int value = 100; int *p = &value; return p; // 返回區域變數很危險 } ``` :::warning * 雖然上面這段程式可能成功了,但是十分危險 ::: ### 堆 Heap - malloc 使用 * **`malloc`/`free` 是 C 語言提供的標準庫的 API 之一**:可以用來動態申請、釋放記憶體,可在區域、全域變數使用 `malloc` 函數做動態記憶體申請,它的特點如下: 1. **靈活**:可在運行時臨時申請 2. **內存量大**:進程可以按照需要使用 C stander library 提供的 malloc api 手動申請記憶體空間空間 3. **必須手動申請、釋放記憶體空間** > 如果不釋放,則該空間會持續佔據應用中的記憶體空間,最終導致記憶體洩漏 4. **髒內存**:釋放的記憶體空間內的資料並不會被立刻清除,可能會遺留 5. **臨時性**:生命週期只存在 申請 ~ 釋放之間,釋放後再取相同地址會得到不可預期的結果 :::info * 其實 malloc 是由 mmap 而來,並且會由標準庫來負責管理申請的記憶體 ::: ```c= #include <stdio.h> #include <stdlib.h> void dynamic_memory() { int *p = (int *)malloc(1000 * sizeof(int)); if(p == NULL) { printf("malloc memory fault."); return; } *(p + 1) = 123; *(p + 2) = 456; printf("Use memory p1: %d, p2: %d\n", *(p + 1), *(p + 2)); free(p); // 會出現無法預期的錯誤 // 最好是在 free 之後,將 p 置為 NULL printf("After free ptr, Use memory p1: %d, p2: %d\n", *(p + 1), *(p + 2)); } ``` > ![](https://i.imgur.com/QuHh6t1.png) :::danger * 內存洩漏 ? 內存在 RAM 中佔有一塊位置,但並無任何程式在使用這塊 RAM 空間,這就是內存洩漏 ::: ### 標準函數 malloc 細節 * `malloc` 函數是 C 語言的標準函是庫提供,在使用時須重義一些特點 1. **`malloc` 函數 返回值為 `void*` 指標**:該空間存放的數據類型尚未確定,也就是 **可以存放任何類型的數據**,而要存放啥數據等待使用者強制轉型 > 可以解為:類似於 Java 的 Object 類的角色 2. **動態申請記憶體結果**:如果該函數成功則返回第一個 Byte 的地址;失敗則返回 NULL 3. **釋放記憶體**:使用成對的 `free` 函數就可以釋放,不過一定要記得使用原來給予的地址做釋放 * 對於使用 `malloc` 函數申請的空間;申請 0 空間 返回結果不確定,**有可能反為 NULL,須看函數庫如何實現** ```c= void malloc_0_size() { int *p = (int *)malloc(0); if(p == NULL) { printf("malloc size 0 fault.\n"); return; } printf("malloc size 0 success: %p, size: %d.\n", p, sizeof(*p)); *p = 0x7FFFFFFF; printf("Value: %d.\n", *p); } ``` 雖然範例是申請成功的,但建議還是不要這樣使用 > ![](https://i.imgur.com/XbxX6OF.png) ## 編譯器規劃:Segment 段 編譯器在編譯程式時,**會按照一定的結構、規則拆分程式,組成不同的 ++段++**;常見的段就有 `.text`、`.bss`、`.data` ### .text 程式段 * `.text` 是編譯器分析過後,專門放置程式的位置,關於程式的指令也就放在這 ```c= // .text void sample_func(int v) { char *s = NULL; if(v == 0) { // 判斷指令放在 .text s = "Hello"; } else { s = "World"; } printf("%s\n", s); } ``` ### .data 數據段 * `.text` 是編譯器分析過後,專門放置數據的位置,同時也稱為 `靜態數據區`、`靜態區`; ```c= // 放置在 .txt 段 static char* HELLO = "HELLO~"; void my_function() { static int a = 10; // 分配在 .data 段 int b = 100; // 分配在 Stack } ``` :::info * 與 Heap 幾乎相同,但是 `.data` 段生命週期是一直到程式結束才會結束 ::: ### .bss 段 / ZI * `.bss` 段又稱為 **ZI (`Zero Initial`) 段**,所有為顯示初始化的 **靜態 (全局) 變量** 都放置在此,**這個段會自動將 ++尚未初始化++ 的靜態空間初始化為 0** (或顯示初始化為 0 的也會放置在這) ```c= // 放置在 .bss 段 char* WORLD; int count = 0; ``` :::success * 全局變量如果 **已經初始化,則會放置到 `.text` 區塊** ::: ### .rodata 段 * `.rodata` 段是用來放置「常量數據」 (也就是程式中的不可修改的數據) :::warning * 至於使用關鍵字 `const` 修飾過後是否放置在 `.rodata` 段呢? 只能說可能,**這要依據每個平台的實現 `const` 的方式來決定** ::: ### 字符串位置 - .text/.data * **字符串位置** 1. **字符串也可能放到 `.text` 段**:單晶片的編譯器較常這樣實現;有另外一種可能是放置到 `.data` 段 2. **字符串也可能放到 `.data` 段**:GCC 就是這樣實現字符串 ```c= void ptr_str() { char *p = "My C"; // 放置在 `.data` printf("%s\n", p); } ``` ## C 語言:字符串 其他語言像是 C++、Java、C#... 都有 string 這個關鍵字來描述字符串,而 C 語言中沒有,反而是使用指標提供一連串的字符首地址 ```c= // c 表達字符串的方式 char *c = "Hello String"; ``` ### 字符串特性 * 上面說了,字符串其實就是指向一連串字符空間的首地址 :::success * C 語言使用 [**ASCII**](https://zh.wikipedia.org/wiki/ASCII) **對字符串便碼**,編碼後就可以使用 `char` 將編碼存起來 > ![](https://i.imgur.com/DhavKAM.png) ::: * C 語言的字符串特點如下 1. 只提供使用者 **第一個字符的地址** 2. **字符串尾部固定是 `\0`**:這個 `\0` 是所謂的 **魔數**,在很多程式中都有,魔數個代表了不同的意義 > 字符串中就不可以有 `\0` 這個符號,否則會分不清是否是結尾 3. **字符的地址是連續** 的,如同 Array :::info * **字符中的 `\0`、`0` 的差別**,我們把字符中與 ASCII 編碼對照,就可以插出兩者的差別 | 字符 | ASCII 編碼| | -------- | -------- | | `\0` | 0 | | `0` | 48 | ::: ### 字符串 - 定義方式 * **字符串定義方式有兩種:** 1. **使用指標 `char*`** 定義字符串 * **字符串的大小**:字符串大小 + '\0' + 指針大小 * '\0' 上面我們已經得知這是必要的規則,所以占用 1 個 Byte * **指標大小**:其實我們所取得的 **並不是第一個 char 的地址,而是取得指向第一個 char 地址的指針**,如下圖 > ![](https://i.imgur.com/bhc8NVh.png) ```c= void test_string_ptr() { char *p = "Hello"; printf("p: %p,&p: %p\n", p, &p); } ``` > 下圖 `004063EC` H 字符的地址; > `0064FF0C` 是 p 的地址 > > ![](https://i.imgur.com/gQNnTtY.png) 2. **使用陣列 `Array`** 定義字符串 * **字符串的大小**:'\0' + 指針大小 > ![](https://i.imgur.com/lizc0rt.png) * 我們可以看到 Array、Ptr 所定義的 string 是不同的;Array 所定義的 String,其符號是指向第一個 char 字節地址,所以 **Array 定義的 String 可以修改** ```c= void test_string_array() { char p[] = "Linux"; printf("p: %p,&p: %p, %s\n", p, &p, p); p[0] = 'G'; printf("p: %p,&p: %p, %s\n", p, &p, p); } ``` > ![](https://i.imgur.com/KYsv5X4.png) * Ptr & Array 定義字符串差異 > ![](https://i.imgur.com/ULtckAr.png) ### sizeof & strlen 差異 * **`sizeof` 是 C 語言的 「運算符」,不是函數**;**而 `strlen` 則是標準函數庫所提供的函數**,專門用來計算字符串長度 `sizeof` 會計算包括 `\0` 的長度 ```c= void string_len() { char p[] = "HelloWorld"; int len = sizeof(p); printf("string length: %d\n", len); len = strlen(p); printf("string length: %d\n", len); char *p2 = "HelloWorld"; len = strlen(p2); printf("string length: %d\n", len); } ``` > ![](https://i.imgur.com/yMwEOF3.png) * `strlen` 函數在使用時,傳入的必須是指標,並且該指標一定要指向一個字符串,否則沒有意義 ```c= void err_use_strlen() { int apple = 10; int *p = &apple; int len = strlen(p); // 傳入非字串指標,沒意義 printf("string length: %d\n", len); } ``` ## 更多的 C 語言相關文章 關於 C 語言的應用、研究其實涉及的層面也很廣闊,但主要是有關於到系統層面的應用(所以 C 語言又稱之為系統語言),為了避免文章過長導致混淆重點,所以將文章係分成如下章節來幫助讀者更好地從不同的層面去學習 C 語言 ### C 語言基礎 * **C 語言基礎**:有關於到 C 語言的「語言基礎、細節」 :::info * [**理解C語言中的位元操作:位元運算基礎與宏定義**](https://devtechascendancy.com/bitwise-operations-and-macros-in-c/) * [**C 語言解析:void 意義、NULL 意義 | main 函數調用、函數返回值意義 | 臨時變量的產生**](https://devtechascendancy.com/meaning_void_null_return-value_temp-vars/) * [**C 語言中的 Struct 定義、初始化 | 對齊、大小端 | Union、Enum**](https://devtechascendancy.com/c-struct_alignment_endianness_union_enum/) * [**C 語言儲存類別、作用域 | 修飾語、生命週期 | 連結屬性**](https://devtechascendancy.com/c-storage-scope-modifiers-lifecycle-linkage/) * [**指標 & Array & typedef | 指標應用的關鍵 9 點 | 指標應用、細節**](https://devtechascendancy.com/pointers-arrays-const-typedef-sizeof-null/) ::: ### 編譯器、系統開念 * **編譯器、系統開念**:是學習完 C 語言的基礎(或是有一定的程度)之後,從編譯器以及系統的角度重新檢視 C 語言的一些細節 :::warning * [**理解電腦記憶體管理 | 深入瞭解記憶體 | C 語言程式與記憶體**](https://devtechascendancy.com/computer-memory_manager-c-explained/) * [**C 語言記憶體區塊規劃 | Segment 段 | 字符串特性**](https://devtechascendancy.com/c-memory-segmentation-string-properties/) * [**編譯器的角度看程式 | 低階與高階、作業系統、編譯器、直譯器、預處理 | C語言函數探討**](https://devtechascendancy.com/compiler-programming-os-c-functions/) ::: ### C 語言與系統開發 * **C 語言與系統開發**:在這裡會說明 C 語言的實際應用,以及系統為 C 語言所提供的一些函數、庫... 等等工具,看它們是如何實現、應用 :::danger * [**了解 C 語言函式庫 | 靜態、動態函式庫 | 使用與編譯 | Library 庫知識**](https://devtechascendancy.com/understanding-c-library-static-dynamic/) * [**Linux 宏拓展 | offsetof、container_of 宏、鏈表 | 使用與分析**](https://devtechascendancy.com/linux-macro_offsetof_containerof_list/) ::: ## Appendix & FAQ :::info ::: ###### tags: `C`

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password
    or
    Sign in via Google Sign in via Facebook Sign in via X(Twitter) Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    By signing in, you agree to our terms of service.

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully