本文转载自菜鸟教程 【const char * , char const * , char * const 的区别】,并修正部分错误。
const char * , char const * , char * const 有什么区别?它们的含义分别是什么?这是我们常常搞混的三种表示。
关于这三种表示的含义,Bjarne 在他的 The C++ Programming Language 里面给出过一个助记的方法:
“把一个声明从右向左读”。
1
2
3
4
5
6
7
8
char * const cp; // ( * 读成 pointer to )
// cp is a const pointer to char
const char * p;
// p is a pointer to const char;
char const * p;
// 同上,因为 C++ 里面没有 const * 的运算符,所以 const 只能属于前面的类型。
C++ 标准规定,**const 关键字放在类型或变量名之前和之后是等价的 **。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const int n = 5; //same as below
int const m = 10;
const int *p; //same as below const (int) * p
int const *q; // (int) const *p
char ** p1;
// pointer to pointer to char
const char **p2;
// pointer to pointer to const char
char * const * p3;
// pointer to const pointer to char
const char * const * p4;
// pointer to const pointer to const char
char ** const p5;
// const pointer to pointer to char
const char ** const p6;
// const pointer to pointer to const char
char * const * const p7;
// const pointer to const pointer to char
const char * const * const p8;
// const pointer to const pointer to const char
说到这里,我们可以看一道以前 Google 的笔试题:
1
2
const char *p = "hello";
foo(&p); // 函数 foo(const char **pp) 下面说法正确的是[]
- A. 函数 foo() 不能改变 p 指向的字符串内容。
- B. 函数 foo() 不能使指针 p 指向 malloc 生成的地址。
- C. 函数 foo() 可以使 p 指向新的字符串常量。
- D. 函数 foo() 可以把 p 赋值为 NULL。
至于这道题的答案是众说纷纭。针对上面这道题,我们可以用下面的程序测试:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
using namespace std;
void foo(const char **pp)
{
// *pp = NULL;
// *pp = "Hello world!";
*pp = (char *)malloc(10);
// snprintf(*pp, 10, "hi google!"); // argument of type "const char *"
// is incompatible with parameter
// of type "char *"
// (*pp)[1] = 'x'; // expression must be a modifiable lvalue
}
int main()
{
const char *p = "hello";
printf("before foo: %s\n", p);
foo(&p);
// free(p); // argument of type "const char *" is
// incompatible with parameter of type "void *"
printf("after foo: %s\n", p);
// p[1] = 'x'; // expression must be a modifiable lvalue
return 0;
}
结论如下:
- 在 foo 函数中,可以使 main 函数中 p 指向的新的字符串常量。
- 在 foo 函数中,可以使 main 函数中的 p 指向 NULL 。
- 在 foo 函数中,可以使 main 函数中的 p 指向由 malloc 函数生成的内存块,不可以
并可以在 main 中用 free 释放,但是会有警告。但是注意,即使在 foo 中让 p 指向了由 malloc 生成的内存块,但是仍旧不能用 p[1]=’x’; 这样的语句改变 p 指向的内容。 - 在 foo 中,不能用 (*pp)[1]=’x’; 这样的语句改变 p 的内容。
所以,感觉 gcc 只是根据 const 的字面的意思对其作了限制,即对于 const char *p 这样的指针,不管后来 p 实际指向 malloc 的内存或者常量的内存,均不能用 p[1]=’x’; 这样的语句改变其内容。但是很奇怪,在 foo 里面,对 p 指向 malloc 的内存后,可以用 snprintf 之类的函数修改其内容。