目錄
- 前言
- char *str = "" 和 char *str = NULL 區別
- char *str = NULL 和 char str[] = {} 區別
- char *str = "" 和 char str[] = {} 區別
- char *str = "" 和 const char *str = "" 區別
前言
C語言指針的使用非常常見且易出錯,這里對常見的用法做個總結。
指針就是固定大小(一般系統占據4字節)的一塊空間,保存的是其他變量的地址。一個指向性的東西。
- C語言里面“”表示字符串,保存在常量區,不能修改;
- {}表示數組,自動分配棧空間,可以修改;
- 指針本身是個變量,一般固定占用4個字節,保存其他變量的地址,可以修改從而指向不同的地址空間(非const修飾保存在棧空間)。
char *p1 = NULL;
char *p2 = "";strlen(p1); // 段錯誤(訪問0地址)
strlen(p2); // 返回0(安全)
sizeof(p1); // 安全,strlen計算的是指針指向的字符串空間的長度,而sizeof計算的是指針本身的長度*p1 = 'a'; // 段錯誤
*p2 = 'a'; // 段錯誤(只讀內存)// 指針是個變量,本身保存在棧空間里,修改指針本身從而指向不同的地方
char *reason_str = "";
switch (reset_reason)
{case ESP_RST_UNKNOWN: reason_str = "UNKNOWN"; break;case ESP_RST_POWERON: reason_str = "POWERON"; break;case ESP_RST_EXT: reason_str = "PIN"; break;case ESP_RST_SW: reason_str = "SW"; break;case ESP_RST_PANIC: reason_str = "PANIC"; break;case ESP_RST_WDT: reason_str = "WDT"; break;case ESP_RST_DEEPSLEEP: reason_str = "DEEPSLEEP"; break;case ESP_RST_BROWNOUT: reason_str = "BROWNOUT"; break;case ESP_RST_SDIO: reason_str = "SDIO"; break;
}
char *str = “” 和 char *str = NULL 區別
在C語言中,char *str = “” 和 char *str = NULL 有本質區別,主要體現在內存分配、使用場景和操作安全性上。以下是詳細對比:
?1. 內存表現
特性 | char *str = NULL | char *str = “” |
---|---|---|
?指針值 | 0x00000000(無效地址) | 有效地址(如 0x00405060) |
?指向內容 | 無內存分配 | 1字節的 ‘\0’(空字符串) |
??內存區域 | 無 | 只讀數據段(.rodata) |
?2. 核心區別
-
?NULL?
-
- 表示指針未初始化或指向無效地址。
-
- ?解引用會崩潰?(如 strlen(NULL) 觸發段錯誤)。
-
- 典型用途:標識錯誤返回值或未初始化的狀態。
-
?""?
-
- 指向合法的空字符串(僅含終止符 ‘\0’)。
-
- ?可安全操作?(如 strlen(“”) 返回 0)。
-
- 典型用途:表示邏輯上的“空值”而非“無值”。
?3. 使用場景對比?
?場景1:函數返回值
const char* get_error_msg(int code) {if (code == 0) return NULL; // 無錯誤消息if (code == 1) return ""; // 空錯誤消息(合法但無內容)return "Error occurred";
}
NULL:表示“無消息”
“”:表示“有消息但內容為空”
場景2:字符串處理
void print_str(const char *s) {if (s == NULL) {printf("NULL input\n");} else if (s[0] == '\0') {printf("Empty string\n");} else {printf("%s\n", s);}
}
輸入 NULL → 輸出 NULL input
輸入 “” → 輸出 Empty string
?場景3:默認值初始化
char *log_msg = NULL; // 默認未記錄日志
char *user_input = ""; // 默認空輸入(避免NULL解引用崩潰)
?4. 操作安全性
操作 | NULL 結果 | “” 結果 |
---|---|---|
?strlen(str) | 段錯誤 | 返回 0 |
?strcpy(dest, str) | 段錯誤 | 復制 ‘\0’ |
??printf(“%s”, str) | 段錯誤 | 輸出空(無崩潰) |
?5. 總結?
?- 用 NULL 當?:
-
- 需要明確表示“無值”或“無效”。
-
- 作為錯誤返回值或未初始化狀態。
?- 用 “” 當?:
- 作為錯誤返回值或未初始化狀態。
-
- 需要安全處理字符串操作(避免NULL檢查)。
-
- 表示邏輯上的“空字符串”而非“無字符串”。
?
- 表示邏輯上的“空字符串”而非“無字符串”。
關鍵區別?:NULL 是“指針無意義”,“” 是“指針有意義但內容為空”。
char *str = NULL 和 char str[] = {} 區別
在C語言中,char *str = NULL和char str[] = {}有本質區別,主要體現在內存分配、可修改性和使用場景上:
?1. 內存分配方式
特性 | char *str = NULL | char str[] = {} |
---|---|---|
??類型 | 指針(未指向有效內存) | 數組(自動分配棧內存) |
?內存區域 | 無實際分配 | 棧空間(通常可讀寫) |
大小 | 指針大小(如4/8字節) | 1字節(僅含\0) |
?2. 核心區別?
-
?char *str = NULL?
-
- 定義了一個未初始化的?指針變量?,值為0x0
-
- ?不能直接操作內容?(解引用會崩潰,如str[0]觸發段錯誤)
-
- 典型用途:動態內存分配的占位符或錯誤標識
-
?char str[] = {}?
-
- 定義了一個?空字符數組?,實際包含1字節的’\0’
-
- ?可安全操作內容?(如str[0] = 'a’修改棧內存)
-
- 典型用途:局部緩沖區的空初始化
3. 操作對比?
?示例代碼
#include <stdio.h>int main() {char *ptr = NULL; // 指針未指向有效內存char arr[] = {}; // 空數組(含'\0')// 操作測試printf("ptr size: %zu\n", sizeof(ptr)); // 輸出指針大小(如8)printf("arr size: %zu\n", sizeof(arr)); // 輸出1(含'\0')// arr[0] = 'a'; // 合法(修改棧內存)// ptr[0] = 'a'; // 崩潰(解引用NULL)return 0;
}
關鍵操作安全性
操作 | NULL 結果 | {} 結果 |
---|---|---|
sizeof | 返回指針大小 | 返回1(含\0) |
下標訪問(如[0]) | 段錯誤 | 可讀寫 |
strlen | 段錯誤 | 返回0 |
4. 使用場景
?用 char *str = NULL 當?:
-
需要后續動態分配內存(如str = malloc(10))
-
作為函數參數表示“未初始化”狀態
?
用 char str[] = {} 當?: -
需要局部空字符串緩沖區
-
避免指針解引用風險時(如嵌入式開發)
?5. 特殊注意
C99/C11標準中,char str[] = {}是?非標準語法?(但部分編譯器支持),更規范的寫法是:
char str[] = ""; // 標準寫法,等效含'\0'的空數組
若需明確空數組初始化,建議使用:
char str[1] = {0}; // 顯式初始化為0
總結?
NULL指針表示“無內存關聯”,而空數組{}是“已分配的可操作內存”。前者需動態分配后使用,后者直接具備棧內存安全性。
char *str = “” 和 char str[] = {} 區別
在C語言中,char *str = ""和char str[] = {}有以下核心區別:
1、?內存分配與生命周期?
char *str = “”:指針指向只讀數據段的空字符串常量(.rodata段),生命周期為整個程序運行期
char str[] = {}:數組分配在棧空間(自動存儲期),生命周期限于當前作用域
?2、可修改性?
char *str = “”:內容不可修改(嘗試修改會導致未定義行為)
char str[] = {}:內容可修改(棧內存可讀寫)
3、?語法有效性?
char *str = “”:標準C語法
char str[] = {}:非標準語法(部分編譯器擴展支持),更規范的寫法是char str[] = ""或char str[1] = {0}
4、?sizeof行為?
sizeof(str)在指針情況下返回指針大小(如8字節)
sizeof(str)在數組情況下返回實際分配大小(空數組為1字節,含’\0’)
?5、典型使用場景?
指針形式常用于定義全局字符串常量
數組形式常用于局部可修改緩沖區
注意:空數組初始化{}在C99/C11中不是標準語法,建議改用""或{0}明確初始化。
char *str = “” 和 const char *str = “” 區別
在C語言中,char *str = ""和const char *str = ""的關鍵區別在于?類型安全性和編譯器約束?,具體對比如下:
1. 本質區別
特性 | char *str = “” | const char *str = “” |
---|---|---|
?類型修飾 | 普通指針 | 常量指針 |
?內容可修改性 | 語法允許修改(但實際會引發未定義行為) | 明確禁止修改(編譯器報錯) |
編譯器檢查 | 無保護 | 強制類型檢查 |
?2. 實際表現?
?示例代碼
char *p = ""; // 無const修飾
const char *cp = ""; // 有const修飾// p[0] = 'a'; // 編譯通過,但運行時可能崩潰(字符串常量區不可寫)
// cp[0] = 'a'; // 直接編譯報錯(const保護)
關鍵差異?
?char *str?
- 僅表示指向字符的指針,不承諾指向的內容是否可改
- 若指向字符串常量(如""),嘗試修改會導致?未定義行為?(通常是段錯誤)
const char *str?
- 明確告知編譯器指向的內容不可修改
- 任何修改嘗試會觸發?編譯時錯誤?,提前暴露問題
?3. 使用場景建議?
?用 char * 當?:
- 需要兼容舊代碼(歷史遺留API)
- 明確知道后續會指向可修改內存(如malloc分配的堆內存)
?
用 const char * 當?:
- 指向字符串常量(如""或字面量)
- 作為函數參數防止意外修改(如strlen的原型)
?4. 為什么推薦const版本??
?1、安全性?:避免意外修改只讀數據(如p[0] = 'x’的隱蔽錯誤)
?2、可讀性?:明確表達設計意圖(“我只讀不寫”)
?3、編譯器優化?:const可能幫助編譯器生成更優代碼
?5. 特殊注意?
- 以下寫法是?等效?的(均指向只讀空字符串):
const char *s1 = "";
char const *s2 = ""; // const位置不同,但含義相同
- 但若寫成char * const s3 = “”,則表示?指針本身不可改?(而非指向內容)。