为何scanf_s写入const char*指向内存时两段代码表现不同?
C++两段同逻辑代码运行差异的根本原因
首先明确:两段代码的const修饰的目标存储区域属性完全不同,这是表现差异的核心。
第一段代码可运行的原因
#include <iostream> using namespace std; int main() { // 注:原代码存在笔误,数组名itemss和后续使用的items不统一,属于手误不影响核心逻辑 const char items[8] = "1234567"; const char* item = items; scanf_s("%s", item, 8); printf(item); return 0; }
- 这里的
const char items[8]是栈上分配的局部数组,栈内存本身的页属性是可读写的。 - 此处的
const仅为编译期语法限定:仅限制你直接通过items变量名修改数组内容,不会改变内存本身的读写权限。 scanf_s接收指针参数时会丢弃const类型限定,相当于绕过了编译期的const检查,直接向可读写的栈内存写入数据,自然不会触发运行时错误。
注意:这段代码本质是未定义行为,能正常运行只是当前编译环境、运行环境下的偶然表现,不能保证所有场景下都正常执行。
第二段代码触发段错误的原因
#include <iostream> using namespace std; int main() { const char* item = "1234567"; scanf_s("%s", item, 8); printf(item); return 0; }
- 这里的
"1234567"是C++标准规定的字符串字面量,会被编译器分配到进程地址空间的只读数据段(.rodata段),该段内存的页表属性被操作系统标记为只读,任何写入操作都会触发硬件级别的内存保护异常,也就是段错误。 - 此处的
const只是语法上符合字符串字面量的类型要求,哪怕你去掉const写成char* item = "1234567"(C++11之前允许这种隐式转换),写入操作依然会触发段错误,和const修饰符无关,核心是底层内存本身不可写。
核心差异总结
- 栈上const数组的const是语法层面的编译期检查,不改变内存的可读写属性,绕过检查后写入可以执行。
- 字符串字面量的底层存储本身就是只读的,属于运行时的硬件/操作系统级别的保护,任何写入操作都会报错。
内容的提问来源于stack exchange,提问作者fotefall
相关产品推荐
相关产品推荐

