C语言中的字符串常量和数组
在C语言中,我们可以创建一个指向常量字符串的指针,如C语言中的字符串常量和数组,c,arrays,string,C,Arrays,String,在C语言中,我们可以创建一个指向常量字符串的指针,如 char *s = "abc"; 但既然字符串基本上都是以null结尾的字符数组,为什么不允许这样做呢 char *s = {'a', 'b', 'c' , '\0' }; 您可以编写以下代码: char s[] = { 'a', 'b', 'c', '\0` }; 这和 char s[] = "abc"; 但是,字符串文字实际上是只读的(因为在文本段中)。因此,您应该将字符串文字理解为const char s[](即使它不完全是
char *s = "abc";
但既然字符串基本上都是以null结尾的字符数组,为什么不允许这样做呢
char *s = {'a', 'b', 'c' , '\0' };
您可以编写以下代码:
char s[] = { 'a', 'b', 'c', '\0` };
这和
char s[] = "abc";
但是,字符串文字实际上是只读的(因为在文本段中)。因此,您应该将字符串文字理解为const char s[]
(即使它不完全是这样,如果您非常关心C标准的话)。特别是编码“abc”[1]=“X”
是(在Linux上可能会因分段冲突而崩溃)
如果您启用所有警告,例如使用GCC-Wall
当然,C语言中的指针和数组是不同的(数组可以衰减为指针),正如所解释的那样。您可以编写以下代码:
char s[] = { 'a', 'b', 'c', '\0` };
这和
char s[] = "abc";
但是,字符串文字实际上是只读的(因为在文本段中)。因此,您应该将字符串文字理解为const char s[]
(即使它不完全是这样,如果您非常关心C标准的话)。特别是编码“abc”[1]=“X”
是(在Linux上可能会因分段冲突而崩溃)
如果您启用所有警告,例如使用GCC-Wall
当然,C语言中的指针和数组是不同的(数组可以衰减为指针),正如所解释的。这是因为指针不是数组。(可以将数组衰减为指向第一个元素地址的指针,但指针不能成为数组。) 您可以这样做:
char s[] = {'a', 'b', 'c', '\0'};
// ^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^
// array valid initializer for char[]
但不是这个:
char* s = {'a', 'b', 'c', '\0'};
// ^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^
// pointer invalid initializer for char*
这是因为指针不是数组。(可以将数组衰减为指向第一个元素地址的指针,但这不会使指针成为数组。) 您可以这样做:
char s[] = {'a', 'b', 'c', '\0'};
// ^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^
// array valid initializer for char[]
但不是这个:
char* s = {'a', 'b', 'c', '\0'};
// ^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^
// pointer invalid initializer for char*
这基本上是因为语言不允许这样做 字符串文字是类型为
char[N+1]
的表达式,其中N
是文字的长度。它是指具有静态存储持续时间的匿名数组对象,这意味着该对象在整个程序执行过程中都存在
(注意,与C++不同,它不是<代码> const char [n+1] ,但是试图修改它有未定义的行为。< /P> 和任何数组类型的表达式一样,在大多数上下文中,它隐式转换为指向数组第一个元素的指针
因此,在本宣言中:char *s = "abc";
表达式“abc”
隐式转换为指向
数组,用于初始化s
。但这样写更安全:
const char *s = "abc";
这样您就不会意外地试图修改数组
那么为什么这不起作用呢
char *s = { 'a', 'b', 'c', '\0' };
这是因为{'a','b','c','0'}
不是一个表达式。它是一个初始值设定项,可用于初始化数组对象,但不能用于初始化指针对象。如果你改写:
char arr[] = { 'a', 'b', 'c', '\0' };
然后使用初始化器初始化数组对象;它不创建数组对象。要使char*s
版本正常工作,它必须为指针s
创建一个对象。括号内的初始值设定项列表不能这样做
C99增加了一个新特性,复合文字,在某些方面类似于字符串文字,但更通用。例如,这:
(char[]){ 'a', 'b', 'c', '\0' }
是一个类型为char[4]
的表达式,同样,与任何数组类型的表达式一样,它在大多数上下文中隐式转换为指针。因此:
char *arr = (char[]){ 'a', 'b', 'c', '\0' };
有效,并使arr
指向由复合文字创建的匿名数组对象的第一个元素
有一个显著的区别:数组对象的生存期不一定是静态的。如果一个复合文字出现在任何函数之外,那么数组对象在整个程序执行过程中确实存在;否则,它就像一个具有自动存储持续时间的本地对象
如果您使用的编译器不支持C99(*cough*Microsoft*cough*),则始终可以先声明数组对象:
const char arr[] = { 'a', 'b', 'c', '\0' };
const char *s = arr;
另请参见的第6节,该节讨论了数组和指针(并且在消除一些关于它们的常见误解方面做得很好)。这基本上是因为该语言不允许这样做 字符串文字是类型为
char[N+1]
的表达式,其中N
是文字的长度。它是指具有静态存储持续时间的匿名数组对象,这意味着该对象在整个程序执行过程中都存在
(注意,与C++不同,它不是<代码> const char [n+1] ,但是试图修改它有未定义的行为。< /P> 和任何数组类型的表达式一样,在大多数上下文中,它隐式转换为指向数组第一个元素的指针
因此,在本宣言中:char *s = "abc";
表达式“abc”
隐式转换为指向
数组,用于初始化s
。但这样写更安全:
const char *s = "abc";
这样您就不会意外地试图修改数组
那么为什么这不起作用呢
char *s = { 'a', 'b', 'c', '\0' };
这是因为{'a','b','c','0'}
不是一个表达式。它是一个初始值设定项,可用于初始化数组对象,但不能用于初始化指针对象。如果你改写:
char arr[] = { 'a', 'b', 'c', '\0' };
然后使用初始化器初始化数组对象;它不创建数组对象。要使char*s
版本正常工作,它必须为指针s
创建一个对象。括号内的初始值设定项列表不能这样做
C99增加了一个新特性,复合文字,在某些方面类似于字符串文字,但更通用。例如,这:<