98.C语言易混难点:字符数组与字符串指针的底层差异

一、两种写法的直观对比

我们先看两个最常见的字符串定义:

c 复制代码
char s[] = "hello";  // 字符数组
char *p = "hello";   // 字符串指针

从表面上看,二者都能通过printf("%s", s)printf("%s", p)打印出hello,但它们的底层存储位置、修改权限完全不同:

  • char s[]:在栈上分配数组空间,字符串内容会被拷贝到数组中,可以修改
  • char *p:指针变量保存在栈上,指向只读的字符串常量区,强行修改会导致程序崩溃

二、字符数组:拥有独立存储空间

字符数组的本质是在栈上开辟一块连续的内存空间,将字符串常量的内容拷贝到这块空间中。因此,数组拥有这块内存的所有权,可以自由修改其中的字符。

示例代码

c 复制代码
#include <stdio.h>

int main() {
    char s[] = "hello";
    s[0] = 'H';  // 可以修改数组中的字符
    printf("%s\n", s);  // 输出:Hello
    return 0;
}

底层逻辑

  • 栈上分配6字节空间(h e l l o \0)。
  • 字符串常量"hello"的内容被拷贝到数组中。
  • 数组名s是这块内存的首地址,修改s[0]会直接修改数组中的内容。

三、字符串指针:指向只读常量区

字符串指针的本质是在栈上分配一个指针变量,保存字符串常量的首地址。而字符串常量本身存储在只读的常量区,不允许修改。

错误示例(会导致崩溃)

c 复制代码
#include <stdio.h>

int main() {
    char *p = "hello";
    p[0] = 'H';  // 危险!修改只读常量区,程序会崩溃
    printf("%s\n", p);
    return 0;
}

底层逻辑

  • 栈上分配8字节(64位系统)的指针变量p
  • 字符串常量"hello"存储在只读的常量区,p保存其首地址。
  • 尝试修改p[0]会触发段错误,因为常量区的内存是只读的。

四、核心差异对比表

特性 char s[] = "hello" char *p = "hello"
存储位置 栈上数组空间 栈上指针 + 常量区字符串
所有权 数组拥有内容所有权 指针仅保存地址,无所有权
修改权限 可以自由修改 禁止修改,修改会崩溃
适用场景 需要修改字符串内容 仅需读取字符串内容

五、正确使用建议

1. 需要修改字符串时,优先使用字符数组

如果后续需要修改字符串内容,必须使用字符数组,并提前分配足够的空间:

c 复制代码
#include <stdio.h>
#include <string.h>

int main() {
    // 分配20字节空间,足够容纳修改后的字符串
    char s[20] = "hello";
    s[0] = 'H';
    strcat(s, " C");  // 拼接字符串
    printf("%s\n", s);  // 输出:Hello C
    return 0;
}

2. 仅需读取字符串时,可使用指针

如果只是需要读取字符串内容,使用指针更节省栈空间:

c 复制代码
#include <stdio.h>

int main() {
    const char *p = "hello";  // 加const更安全,防止误修改
    printf("%s\n", p);  // 输出:hello
    return 0;
}

六、一句话总结

字符数组和字符串指针的核心差异,不在于能否打印字符串,而在于谁拥有这块字符空间

  • 数组有自己的存储空间,内容可以修改;
  • 指针仅保存常量区的地址,内容禁止修改。

在实际开发中,务必根据需求选择合适的写法,避免因混淆二者导致程序崩溃。

相关推荐
麻瓜code5 分钟前
【LeetCode】相交链表:双指针法,一次遍历找到交点
算法·leetcode·链表
玖玥拾9 分钟前
Lua 基础语法(六)xLua Lua 调用 C# 交互
开发语言·unity·c#·lua
国产化创客9 分钟前
创客开发入门(三)Arduino IDE 开发环境
ide·单片机·嵌入式硬件·课程设计·智能硬件
CedarQR11 分钟前
LubanCat-2 (RK3568) Debian 下让 H3C Magic USB 无线网卡(AIC8800)联网全记录
linux·网络·单片机·嵌入式硬件·debian·3568·h3c
Joolun商城源码_Java12 分钟前
Java 商城技术栈怎么选:单体、微服务还是前后端分离多端?
java·开发语言·微服务
charlie11451419113 分钟前
浅谈C++的列表初始化std::initializer_list
开发语言·数据结构·c++·list·开源项目
拒绝内耗。17 分钟前
一个请求进入 Java 应用后,怎么找到我们写的方法?
java·开发语言
励志不掉头发的内向程序员21 分钟前
【LibreCAD 2D架构】RS_Line创建之后发生了什么?从图形容器到屏幕渲染
开发语言·c++·qt·学习·系统架构
夕除22 分钟前
redis--013
java·开发语言
object not found23 分钟前
Nuxt4去掉body中默认的边距
开发语言·后端·rust