You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

字符数组与字符指针定义字符串的差异及memmove报错原因

字符串数组 vs 字符指针的区别,以及段错误原因解析

嘿,这两个问题本质上是在问C语言中字符串两种常见存储方式的核心差异,咱们一步步讲明白:

问题1:字符串数组和字符指针的区别

这两种定义方式在内存存储、可修改性、灵活性上都有明显不同:

  • 存储位置与可修改性
    • 数组(char string[] = "xxx";):如果是局部变量,会在栈内存上分配一块连续空间,把字符串字面量的内容完整复制进去;如果是全局变量则存在全局数据区。这块内存是可写的,你可以随意修改数组里的字符。
    • 字符指针(char* string = "xxx";):指针变量本身存在栈/全局区,但它指向的是存储在**只读数据段(.rodata)**里的字符串字面量。这块内存是操作系统保护的只读区域,尝试修改会触发未定义行为(比如段错误)。
  • 内存分配逻辑
    • 数组:定义时会根据字符串长度自动分配字符串长度+1的内存(多出来的1字节存结束符'\0'),内存大小固定,无法动态调整。
    • 指针:指针本身只是一个4/8字节的地址变量(取决于平台是32位还是64位),它不存储字符串内容,只是指向已有字符串的起始地址。你可以让它指向动态分配的内存(比如malloc),也可以指向其他字符串字面量,灵活性更高。
  • 初始化与指向特性
    • 数组:除了字符串字面量初始化,还可以逐个字符初始化(比如char string[] = {'H','e','l','l','o','\0'};),一旦定义,数组名是一个常量指针,不能改变它的指向。
    • 指针:可以直接指向字符串字面量,也可以指向已有的字符数组或动态内存,并且可以随时修改指针的指向,让它指向其他内存地址。

问题2:为什么改成字符指针会触发段错误?

咱们对比两段代码的核心差异:

第一段代码(数组版本)

#include <stdio.h>
#include <string.h>
int main ( ){
    char string [] = "Home Sweet Home";
    printf ("%s",(char*)memmove(string,&string[5],10));
}

这里char string[] = "Home Sweet Home";做了一件事:在栈上开辟了一块足够大的内存,把字符串字面量"Home Sweet Home"的每一个字符(包括末尾的'\0')都复制到了栈内存里。memmove操作的是栈上的可写内存,而且memmove本身就是为处理重叠内存区域设计的,所以能正确完成复制,最终输出Sweet Home Home完全符合预期。

第二段代码(指针版本)

#include <stdio.h>
#include <string.h>
int main ( ) {
    char* string = "Home Sweet Home";
    printf ("%s",(char*)memmove(string,&string[5],10));
}

这里char* string = "Home Sweet Home";是让指针string指向了只读数据段里的字符串字面量。当memmove尝试往这个只读内存区域写入数据时,操作系统的内存保护机制会直接拦截这个操作,触发段错误(Segmentation Fault)——因为只读区域不允许写入操作,这是C标准里明确的未定义行为(虽然语法上允许用char*指向字符串字面量,但修改它是绝对禁止的)。

简单说:数组版本操作的是自己拥有的可写内存,指针版本操作的是系统保护的只读内存,这就是导致段错误的根本原因。

内容的提问来源于stack exchange,提问作者Nimbostratus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 10:19:04