为何C语言中字符串并非“真实存在”?字符与字符串内存差异
嘿,这个问题问得太戳中痛点了!当年我刚学C的时候也被教授这句“字符串并非真实存在”绕得云里雾里,直到后来接触Java才彻底搞明白这里面的门道,咱们一点点拆解清楚:
本质上,C语言没有原生的字符串类型——你写的"hello"并不是一个独立的语言实体,而是一种语法糖,最终会被转换成一个以'\0'(空字符)结尾的char数组。
举个例子:
char greeting[] = "Hello!";
这段代码在编译后,其实等价于:
char greeting[] = {'H', 'e', 'l', 'l', 'o', '!', '\0'};
你操作的从来都是这个字符数组,所谓的“字符串”只是C程序员之间约定俗成的概念:只要是char数组,且最后一个元素是'\0',我们就把它当作字符串来用。C语言本身根本不知道“字符串”是什么,它只认识数组和单个字符。教授说的“不存在”,就是指它不是语言层面定义的、有独立属性和行为的类型,只是一种编程惯例。
和C完全相反,Java里的字符串是货真价实的语言实体——它有专门的String类,是Java核心库的一部分,属于引用类型,有自己的属性和方法(比如length()、equals()、substring())。
虽然Java的String底层也是基于字符/字节数组(JDK9及以后默认用byte[]配合编码标志优化内存),但这些细节都被封装在String对象里了。你写:
String greeting = "Hello!";
你操作的是一个String对象,而不是直接操作底层的数组——甚至因为String是不可变的,你连底层数组的内容都没法直接修改,只能创建新的String对象。从语言层面来说,字符串是一个独立的、被官方认可的“存在”。
确实,不管是C还是Java,字符串最终都以连续的字符/字节序列存储,但内存占用的差异主要来自封装层次和语言特性:
- C语言:内存开销极小,就是字符数组的长度(包含
'\0'终止符)。比如"Hello!"占7字节(6个字符+1个'\0'),没有额外的对象头或元数据开销。但缺点是没有自动的内存管理,也没有字符串复用机制,相同的字符串会重复占用内存。 - Java语言:因为有
String对象的封装,会额外占用对象头(Mark Word、类型指针等,约16字节)、哈希值缓存、编码标志等字段的内存。比如一个空字符串,Java的String对象占用的内存远大于C里的char[] = "\0"(仅1字节)。不过Java有字符串常量池,相同的字面量会复用同一个对象,能减少重复创建的内存浪费;JDK9之后的byte[]优化也能让Latin-1字符(比如英文字母)只用1字节存储,进一步节省内存。
总结一下:C里的“字符串”是程序员约定的数组用法,Java里的字符串是语言原生的对象;底层存储都是字符/字节序列,但Java因为封装和特性,内存开销有得有失。
内容的提问来源于stack exchange,提问作者wutBruh

