char*和const char*作为参数的区别

41

有很多次,当我使用 char* 而不是 const char* 时,会出现编译错误。所以,我不确定它们之间的真正区别、语法和编译机制。


你使用的是什么系统和编译器? - kgiannakakis
8
“我得到编译错误”是指哪些编译(r)错误?代码是什么样子的?你调用的函数签名是什么?你在提问时投入的精力越多,你获得的答案就越丰富、质量也更高。 - T.J. Crowder
我收到了错误信息:'无法将参数1从'char *'转换为'const char *'。 - Sunscreen
2
@Sunscreen:引用一下,“代码是什么样子的?你调用的函数签名是什么?” - T.J. Crowder
如果你得到的是编译器错误而不是警告,那么你应该标记为C++而不是C。在C语言中,丢弃const的隐式转换并不是错误。 - R.. GitHub STOP HELPING ICE
显示剩余2条评论
5个回答

53

如果你想要区分这两者的不同,可以把它们理解为:

  • char* 是一个指向包含类型为 char 的值且可更改的位置的指针。指针的值可以被更改,也就是说指针可以被修改指向不同的位置。
  • const char* 是一个指针,它的值也可以被更改,但它指向的位置包含的类型为 char 的值是不能被更改的。

如果我为两者分配内存,然后再进行赋值呢? - Sunscreen
@防晒霜:您将能够通过char *指针而不是const char *指针向内存写入。 - T.J. Crowder
15
使用const char*有几个原因。其中一个是它可以记录您的代码不会修改所指向的数据。另一个原因是,它将防止您在不经意间(例如由于打错符号,如= 而不是==,或者输错变量名称)写入您本不想修改的地方。此外,这也可能帮助编译器确定可进行的优化(但如果编译器已经足够智能,则可能没有这种必要)。 - R.. GitHub STOP HELPING ICE
1
@Sunscreen:“那么,使用'const char '有什么意义呢?”对我来说,主要有两个原因:1.正如“R.”所指出的那样,它记录了您的代码,是您的函数或其他内容的合同的一部分。2.在函数签名中使用const char *参数时,如果函数不需要修改传递的字符串,则可能*允许编译器进行无法执行的优化。 - T.J. Crowder
与您的第二点相矛盾,我无法更改由*const char **指向的地址处的值。int main() { const char* str = "Original string."; strcpy(str, "New string."); //error: invalid conversion from 'const char*' to 'char*' [-fpermissive]| return 0; } - pkthapa
@PankajKumarThapa 这是因为你指向了一个字符串字面量。尝试使用char数组再次尝试。 - syockit

29

const char * 的意思是“指向不可修改的字符”的指针。它通常用于不应被修改的字符字符串。

假设你正在编写这个函数:

int checkForMatch(const char * pstr)

通过函数签名,你已经承诺不会更改pstr所指的内容。现在假设匹配的一部分需要忽略字母的大小写,并且你尝试在进行其他检查之前将字符串转换为大写:

strupr(pstr);

你会收到一个错误,提示你不能这样做,因为strupr被声明为:

char * strupr(char* str);

这意味着它希望能够写入字符串。你不能写入 const char * 中的字符(这就是 const 的作用)。

一般来说,你可以将一个 char * 传递给期望一个 const char * 的函数或方法而不需要显式地进行强制类型转换,因为这是安全的(将可修改的内容传递给不打算修改它的代码)。但是你不能将一个 const char * 传递给期望一个 char * 的函数或方法(不经过显式转换) ,因为这是不安全的(将不打算被修改的内容传递给可能会修改它的代码)。

当然,这是 C 语言,你可以在 C 中做任何事情,包括显式地将 const char * 转换为 char * — 但这是一个非常,非常糟糕的想法,因为指针所指向的东西很可能有某些原因被标记为 const


...但是让我们完全摆脱字符串字面值 - 已更新。 - T.J. Crowder
2
@Sunscreen:char ch = 'A';是一个变量(ch),它包含一个可以更改的字符。因此,char *是指向可以更改的字符的指针。同样地,const char ch = 'A';是一个变量(ch),用于存储您无法更改的字符,因此const char *是指向您无法更改的字符的指针(通常意味着它是指向以空字符结尾的字符串的指针,但这不一定是这种情况)。 - T.J. Crowder
1
@shin C和C++标准都规定,对字面量进行写操作将导致未定义的行为。 - anon
1
@shin 无论你做什么,从标准的角度来看,它总是未定义行为。当然,它可能适用于你特定的实现。 - anon
即使是const char,也可以传递char的出色解释。 - user966588
显示剩余14条评论

4
  • char *       : 非常量字符的非常量指针
  • const char *    : 常量字符的非常量指针
  • char *const     : 非常量字符的常量指针
  • const char * const : 常量字符的常量指针


参考链接 [link]


2

我总是尝试使用const char*来定义参数,而不是char*,因为通过.c_str()方法将std::string转换为const char*很容易。然而,将std::string转换为char*并不那么容易。


1

可能我太挑剔了。在我的书中,由const char*指向的字符可能会被更改,但不能通过const char*进行更改。const char*可以指向可修改的存储。例如:

char a[] = "abracadabra";
const char * ccp = &a[0]; // ccp points to modifiable storage.
*&a[0] = 'o'; // This writes to a location pointed to by const char* ccp

所以,我的措辞是:

char * 是一个指针,可以被更改,并且在通过 * 或 [] 解除引用时也允许写入。

const char * 是一个指针,可以被更改,并且在通过 * 或 [] 解除引用时不允许写入。


一个 const char * 也可以简单地转换为普通的 char * 来写入地址。这并不意味着写入将成功;例如指针可能指向不可写内存。但是,如果通过任何其他方式写入该地址具有明确定义的行为,则删除 const 限定符并以这种方式编写也具有明确定义的行为。它对于实现像 strstr 这样需要能够处理 char *const char * 参数并在返回的指针中保留非 const 特性的函数非常有用。 - R.. GitHub STOP HELPING ICE
同样的情况也会发生在另一个方向上,即遗留函数使用char 作为只读参数,并且您信任它不会修改您传递给它作为参数的(char)转换为const char*指针。 - Peter G.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接