2016-10-10 134 views
3

例如,为什么不:的为什么C中的字符串用'const'声明?

char *s= "example"; 

代替:

const char *s= "example"; 

我的理解是常量使得它不变的,但为什么在编译时首先我收到一个错误?

此外,如何构思应用于

int * x; 

VS

const int *x; 

我看到第二个使用得更多,是它使用良好做法“利弊诠释*”?

+2

因为你不能修改字符串文字。 –

+0

,这并不能解释为什么它不能被修改。由于char * s =“example”应该只给出一个字符数组。我明白你不应该,但它不能解释为什么你不能。 –

+0

我不认为你第一个出现错误,它是有效的。 – krato

回答

12

没有要求使用const,但它是一个好主意。

在C中,一个字符串文字是char[N]类型,其中N是串的长度加上1(用于终接'\0'空字符)的表达。但试图修改与字符串文字相对应的数组具有未定义的行为。许多编译器会将该阵列存储在只读存储器中(不是物理ROM,而是由操作系统标记为只读的存储器)。 (数组表达式在大多数情况下转换为指向数组对象的初始元素的指针表达式。)

使字符串文字const更有意义,但const关键字在旧时不存在C版本,它会破坏现有的代码。 (C++确实使字符串文字const)。

此:

char *s= "example"; /* not recommended */ 

实际上是用C完全有效的,但它是潜在的危险。如果在这个声明之后,你这样做:

s[0] = 'E'; 

然后你试图修改字符串,行为是未定义的。

此:

const char *s= "example"; /* recommended */ 

也是有效的;通过评估字符串文字得到的char*值安全且安静地转换为const char*。它通常比第一个版本更好,因为如果您尝试修改字符串文字(在编译时比在运行时捕获错误更好),它可以让编译器警告您。

如果您的第一个示例出现错误,那么很可能是您无意中将代码编译为C++而不是C语言,或者您使用的是gcc的-Wwrite-strings选项或类似的选项。 (-Wwrite-strings使得字符串文字const;它可以提高安全性,但它也可引起GCC拒绝,或至少警告,有效的C代码)

+0

可能值得注意的是,给定'char s1 [] =“example”; char s2 [] =“example”;'每个变量都会得到自己的数组,其中包含字符串“example”,并且这两个副本可以独立修改,但给出'char * p1 =“example”; char * p2 =“example”;'这两个指针都可能标识* same *数组;即使内存不受写保护,修改一个指针的目标也可能会修改另一个指针(或其他任何以“example”中的部分或全部字符结尾的字符串)的目标。 – supercat

+0

给定一些string.h库函数的上下文,例如char * strcat(char * dest,const char * src),连接字符串的函数不会返回值,第一个参数是'unsafe “? –

+1

@ B.Li:'strcat'返回的值只是'dest'参数的值。如果其中一个参数为空或其他无效指针,或者目标阵列没有空间,则可能是不安全的。如果这就是你的想法,那么没有常量正确性问题。 –

2

与警告级别4的Visual Studio 2015年,这个编译和运行是否编译为C或C++:

#include <stdio.h> 

char *s1= "example\n"; 
const char *s2= "example\n"; 

int main(int argc, char **argv) 
{ 
    printf(s1); // prints "example" 
    s1[2] = 'x'; 
    printf(s1); // prints "exxmple" 

    printf(s2); 

    return 0; 
} 

如果我加入这一行,它将无法编译C或C++与每一个编译器我知道:

s2[2] = 'x'; // produces compile error 

这是const关键字旨在避免的错误。它只是告诉编译器不允许分配指向的对象。

如果您的指针指向charint或其他任何内容,则无关紧要。 const关键字对所有指针具有相同的效果,这就使得它不可能(很好,很难)分配给const

0

字符串文字用作值编译成的char的数组不应该被修改。试图修改它会调用未定义的行为。由于向后兼容的历史原因,其类型为char [],但实际上应该是const char []。您可以启用额外的编译器警告来更改此信息,并指示编译器将这些字符串视为const