目录
- 前言
- 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 = “”,则表示指针本身不可改(而非指向内容)。