C和C++中字串符(String)和字符串字面量(String Literal)的区别
我的机器学习教程「美团」算法工程师带你入门机器学习 以及 「三分钟系列」数据结构与算法 已经开始更新了,欢迎大家订阅~这篇专栏整合了这几年的算法知识,简单易懂,也将是我实体书的BLOG版。
欢迎大家扫码关注微信公众号「图灵的猫」,除了有更多AI、算法、Python相关文章分享,还有免费的SSR节点和外网学习资料。其他平台(微信/知乎/B站)也是同名「图灵的猫」,不要迷路哦~
C/C++中的对象指的是一块存储区。字符串字面量是不需要创建过程就可以使用的对象,所以它既没有变量那样的声明或者定义(字符串字面量是无名对象),也不需要向动态分配的对象那样进行动态分配。由于这个原因,用来限定变量的类型限定符(如CONST、VOLATILE)以及存储类别指示符(如EXTERN、STATIC、AUTO、REGISTER)不能用在字符串字面量上。
数组类型
字符串字面量是数组类型的对象,因而具有数组的一切特点。关于这一点在下面还会进一步说明。
静态存储期
C/C++中对象的生存周期按照其存储性质可分为三类:静态存储期(static storage duration)、自动存储期(automatic storage duration)以及动态存储期(dynamic storage duration)。相应地,对象可根据存储期性质分为静态对象、自动对象和动态对象三种。
字符串字面量是静态对象,所以在程序运行期间会一直存在。字符串字面量是左值,而且是不可被更改的左值。
例如,char s[] = “hello”中的”hello”是数组类型的左值(lvalue),用于初始化s数组;
- sizeof(“hello”)
- &“hello”
以及中的“hello”也是左值。在这些情况下,“hello”处于左值语义上下文环境中,所以不会产生下面将要提到的数组转换为指针的现象。另外,有些运算不但要求其操作数是左值,还要求可变。例如,对对象进行赋值、自加、自减等运算。因为数组是不可被更改的左值,所以不能对数组进行这些操作,也就说不存在数组类型的赋值、自加、自减等运算。
字符串字面量可以转换为指向其第一个字符的指针。
处于右值语义环境中的字符串字面量将被默认转换为指向第一个字符的指针。例如,
- char* p = “hello”
中的“hello”在转换为字符指针后用于初始化指针变量p;表达式
“hello”[0]
(相当于*(“hello”+0)或者*“hello”)
中的“hello”也是同样转换为指针后参与下标运算,等等。这种性质也是数组类型的特点。在右值语义环境下,一般类型的对象表示的值是由其存储内容决定的;而数组类型的对象与此不同,它代表的值不是来源于数组对象首元素所在的地址。这是数组最为特殊的地方,也是人们容易产生误解的地方。
取址运算
字符串字面量是一个可取址的对象。例如:&”hello”是合法的表达式。
地址常量
静态对象的地址在编译期间即可被确定,所以其地址(如&“hello”是常量;而字符串字面量又可以从数组类型自动转换为指针
(如“hello”转换为指针后等同于&“hello”[0]),所以字符串字面量可以直接作为地址常量表达式来使用。
修改字符串字面量的行为是无意义的
下面的操作都试图修改字符串字面量中的第一个字符从而修改字符串字面量,所以其结果是无定义的(Undefined)的:
- “hello”[0] = ‘A’ //报错 Undefined
- char * p = “hello”;
- *p = ‘A’; //报错 Undefined
使用了无定义行为的程序是错误的;避免在程序中出现无定义行为是程序员的责任。
区别点:在类型限定上的不同
C中的字符串字面量”hello”是数组类型char[6](相应地,每个字符元素是无const限定的char型);作为右值使用的时候转换为指针类型char*。
在C++中“hello”是char const[6]型(相应地,每个元素的类型是char const);转换为指针使用的时候是char const*,在特殊情况下也可以是char*。
之所以在C中字符串字面量不是const数组(也就是说每个字符元素的类型不是char const),是因为C要照顾或者考虑到标准制定之前已经存在的大量代码–那时的c语言还没有const关键字,如果硬性规定为const数组,则char *p = “hello”这样的初始化或者char *q; q=”hello”这样的赋值就是非法的了(因为右边的类型char const*不能默认转换为左边的类型char*)。
同样,为了使上述代码能顺利通过编译过程,C++采取了另外一种策略:它规定了字符串字面量的类型是const数组,同时有特别规定了字符串字面量也可以有限制地转换为指向非常量的指针(对于”hello”来说就是char*),从而解决了上述代码中存在的问题。不过,转换到char*主要是为了兼容以前的代码,这种转换被C++标准标记为“Deprecated”,所以在写程序时不应该依赖于这种转换。
C++中的字符串字面量是常量,而在C中不是常量。
正是由于标准在类型上的不同规定造成了在C和C++中字符串字面量常量性质上的差别。
在C中,除了string literals和compound literals(C99)之外,其他的字面量都是常量;而在C++中,包括string literals在内的所有literals都是常量(注意:C++中不存在compound literals)。
在现实中,经常可以看到用“字符串常量”来指代“字符串字面量”的情况,其实对于C来说这是不正确的,因为在C中字符串字面量不属于常量;而对于C++来说,“字符串常量”和“字符串字面量”实际上是一回事,只不过看问题的角度不同罢了。
顺便提一下:C++中的常量可以有对象的常量(如字符串字面量、const限定的对象)和非对象的常量之分,而C中的常量不包括对象,它们最明显的特征就是不能进行取值运算,因此常量只能作为右值来使用。
语法及语义上的区别
C中的字符串字面量不是常量,它的每个字符元素也不是常量,所以字符元素的不可变性仅仅表现在语义层面,但在语法和约束条件上没有要求。而C++中的字符串字面量是常量,每个字符元素也是常量,因此在语义和约束条件两方面都要求不能改变其中的每个字符元素;另外,处于兼容性考虑C++还存在着特殊情况下的向非const指针的转换。
下面用具体的嗲吗来对以上内容进行说明。
*”hello” = ‘A’;
表达式*”hello”代表字符串字面量的第一个字符元素对象。上述语句试图通过赋值操作改变第一个元素,当然这样的行为在C和C++中都是无定义的。除了这个相同点外,还有如下的一些细微的区别:
在C++中,*“hello”是一个const对象(其类型是const char。注意:这里的”hello”不会转换为char*指针,所以*”hello”不会是char类型),所以上述赋值违反了赋值号做操作数必须是一个可被改变
的左值的约束条件。在此情况下,标准要求会给出诊断信息。
在C中,*”hello”是一个非const对象(其类型是char),是一个可被改变的左值,所以不违反赋值的约束条件。在此情况下,尽管这个赋值操作是未定义的,标准对诊断信息没有要求。
- char* p = “hello”;
- char* q;
- q = “hello”;
- void foo(char*s);
- foo (“hello”);
上面的初始化和赋值语句中的”hello”都能转换为char*指针类型,所以都是合法的。在C++中,尽管”hello”作为指针使用时是char const*类型,在此情况下(如果不是char*类型则初始化或者赋值不能成立)基于对字符串字面量的特殊规定使它可以转换为char*使用。要注意C++中字符串字面量转换为指向非常量的指针是有限制的,仅仅在有明确的名表类型要求的情况下才能进行这样的转换,否则是非法的。比如下面的情况:
- char *p = “hello” + 1;
- char *q;
- q = “hello”+1;
- void foor(char*s);
- foo(“hello” + 1);
上述是合法的C代码,但是作为C++代码是非法的。非法的原因在于:”hello“转换为char const*指针类型,而不能转换为char*,因为+运算符对于其操作数的类型没有转换为char*这样的直接的要求(因为无论是char const*还是char*都能进行指针加法运算),所以孩子真假挨罚表达式的结果仍然是char const*类型。这样,上面指针的初始化或赋值操作就违反了在类型上的约束条件,需要给出诊断信息。
C和C++中字串符(String)和字符串字面量(String Literal)的区别相关推荐
- c语言里字符串和字符串字面量,string literals(字符串字面量)
构造一个指定字符数组类型的未命名对象,用于需要在源代码中嵌入字符串时使用. 句法 " s-char-sequence "(1)u8 " s-char-sequence & ...
- Java里面是先算乘除后算加减_java.怎么实现字串符的先乘除后加减阿
java.怎么实现字串符的先乘除后加减阿 关注:91 答案:3 信息版本:手机版 电脑版 解决时间 2021-01-18 00:22 提问者壹玍徴戰何亽陪 2021-01-17 10:00 pub ...
- string 字符串中字符无效_7.3 C++字符串类 | 使用string输出
C++字符串类 C++提供了一种新的数据类型:字符串类型,它和char,int类型一样,可以用来定义变量,用一个名字代表一个字符序列,这就是字符串变量. 读者需要明白string并不是C++本身具有的 ...
- java 字符串驻留_java String 以及字符串直接量 与 字符串驻留池 ...
结果输出 :fancydeepin这是怎么回事?不是说 String 是不可变的字符串吗?怎么这里又变了?是这样的,在这里 name 只是一个引用类型变量,并不是一个 String 对象,@1中创建了 ...
- c语言让电脑自动加入空格,tmw字串符怎么导入_C语言如何连空格一直输入到字串符中...
问题补充: #include #include int main() { char c[1000]; int a,b,i; double d; d=0; scanf("%d",&a ...
- 计算机翻译字串符,字符的计算机处理和显示 外文翻译.doc
字符的计算机处理和显示 外文翻译 本科毕业设计(论文) 外文翻译 英文翻译 英文 ON COMPUTERISATION AND REPRESENTATIONOF CHARACTERS The comm ...
- python字符串字面量有哪四种定义方式_python中字符串连接的四种方式
原博文 2018-12-05 14:28 − 以下实例展示了join()的使用方法 #!/usr/bin/python str = "-"; seq = ("a" ...
- c语言回文字符串原理,回文串(c语言)注意字符串比较和字符比较的区别
#include #include #define LEN 224 void judge(char *); int main(void) { char ch[LEN]; gets(ch); judge ...
- Android中添加字串资源出现问题
在系统的framework/base/core/res/res中添加字串等资源,需要在framework/base/core/res/res/values/symbols.xml中同步添加资源字串,否 ...
- java 字符串 字符查找_java之字符串中查找字串的常见方法
1.int indexOf(String str) :返回第一次出现的指定子字符串在此字符串中的索引. int indexOf(String str, int startIndex):从指定的索引处开 ...
最新文章
- 马尔可夫“折棍子”过程 Markovian Stick-breaking Process 在直方图平滑中的应用
- 快速搞懂ThreadLocal实现原理
- pyaudio usb playback_5.5寸触控屏IP电话会议USB全向麦克风NK-OAM600U_影视工业网
- RHEL5简单的引导故障解决
- 2c总线的布线宽度_PCIExpress总线接口的布线规则
- java cookie p3p_利用P3P实现单点登录和COOKIE的跨域读写
- C++ 使用正则表达式拆分字符串
- linux系统设置成中文语言
- PHP读取HTML生成doc
- 【数字信号调制】基于 AM+FM+DSB+SSB实现信号调制解调含Matlab源码
- 北理工嵩天Python语言程序设计笔记(10 Python计算生态概览)
- 微信网页版前端源码分析(一)源码结构和公众号处理逻辑
- 前端开发:webstorm永久破解
- 深入学习JVM探针与字节码技术
- vincent歌曲翻译 很美很美很美
- 【超简单】之基于PaddleSpeech搭建个人语音听写服务
- 图十字链表并求度c语言,第5章_西安电子科技大学出版社:算法与数据结构-C语言描述(樊希平)_doc_大学课件预览_高等教育资讯网...
- TMS320C6455的EMIF与FPGA通讯
- 【最佳实践】企业内网安全解决方案
- ORACLE 数据库 default on null 意思
热门文章
- 第六节:STM32基于HAL库的IIC通信
- C++中的命名空间(namespace)介绍
- ziplist之详细分析
- 2.5.1 命令与参数
- Struts2的学习-属性驱动和模型驱动
- Android Studio在创建项目是一直处于building “project name”gradle project info的解决办法...
- Action中动态方法的调用 Action中通配符的使用 Result的配置
- Telerik for AJAX RadGrid控件
- Codeforces 475C Kamal-ol-molk#39;s Painting 模拟
- Eclipse常用快捷键【转】