理解:const char*, char const*, char*const

首先看看下面这些声明:

 

const char *p; //*pconst,p可变

const (char *) p;//pconst,*p可变

char* const p; //pconst,*p可变

const char* const p; //p*p都是const 


char const * p;// *pconst,p可变

(char*) const p;//pconst,*p可变

char* const p;// pconst,*p可变

char const* const p;// p*p都是const

 

 

上面这些声明意义,及他们的区别你都记住了吗?反正我是记不住,打死也记不住。

听说Bjarne在他的The C++ Programming Language里面给出过一个助记的方法:

把一个声明从右向左读。

char * const cp; ( * 读成 pointer to) cp is a const pointer to char

const char * p; p is a pointer to constchar;

char const * p; 同上因为C++里面没有const*的运算符,所以const只能属于前面的类型。

 

这方法是不错,但还得好好去理解翻译出来的东西,觉得呈现出来的意思不够直接,明了。

 

或者从右向左一步一步来解释,而且每一步都有返回值,是的你没看错,有返回值。每一步都相当于一个函数,上一步的返回值即是下一步的入参。

const char *p;来说吧

1,“p”:代表内存的一块空间,暂且称为”内存1”, 返回值当然是p了,也就是内存1。

2, “*” :当p被星了之后,就跳到新的内存位置,也就是“内存2”。 内存2就是我们说的*p, 这时返回值就是内存2。

3,“char”: 因为上一步的返回值是内存2,所以这个char就作用在内存2上,就像是在说这里存的是一个char类型数据。 返回值还是内存2。

4,“const” :上一步返回内存2(具有char特点的内存2),这时const就作用在内存2上,结果就是说内存2不能变了,他是常量。返回值还是内存2(具有char特点和const特点的内存2)。

5,如果前面还有修饰符,应该可以这样再推下去(起码我是这么想的^-^)

6,前面的都解释完了,不是吗

 

再来看个例子:

const (char *) p;

1, “p”:代表内存的一块空间,称为”内存1”,返回值当然是p,也就是内存1。

2, “(char*)”: 整个修饰p,因为不是*,不会跳转到新的内存,所以返回值还是p,还是内存1。

那“(char* )”什么意思呢,他相当于是一个自定义类型,就像一个自定义函数,简称大函数,由两个小函数构成。

函数1是“*”,函数2是“char”。

函数1“*”的处理结果是跳到另一块内存,即内存2,返回值是内存2。

函数2“char”的处理结果是说内存2是char类型,返回值是内存2。

只可惜这个返回值被大函数隔离了,大函数作为一个整体返回的是入参的那块内存。

如果有一天这个大函数只有一个小函数,这个小函数是“*”,即大函数数“(*)”,这时别以为“*”和“(*)”有什么区别,就是差个马夹而已。

3,“const”:修饰上一步返回的内存,即内存1

 

注意:不要被这里的内存1,内存2诱导,我可没说给他们开辟空间了,声明时是不开辟空间的。

只有在实际赋值之后,内存1,内存2才有对应的实际的内存空间。

所以声明,只是在使用之前先描述一下这个变量具有什么特点,如何来使用这个变量而已。

所以不管是说内存1是const,或内存2是const,并不是说实际的那块内存真的就不能改了(实际上也做不到)。

这里对声明的变量赋值实际上是提供了对某块内存访问的一个方法。Const,char都是描述了这个方法的一些特点;而“*”的作用是跳转到另一块内存。

 

 

说到这里,我们可以看一道以前Google的笔试题:

[题目]const char *p="hello";
       foo(&p);//函数foo(const char **pp)
下面说法正确的是[]
A.函数foo()不能改变p指向的字符串内容
B.函数foo()不能使指针p指向malloc生成的地址
C.函数foo()可以使p指向新的字符串常量
D.函数foo()可以把p赋值为 NULL.

至于这道题的答案是众说纷纭。针对上面这道题,我们可以用下面的程序测试:

#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>


void foo(const char **pp)
{
//    *pp=NULL;
//    *pp="Hello world!";
        *pp = (char *) malloc(10);
        snprintf(*pp, 10, "hi google!");
//       (*pp)[1] = 'x';

}

int
main()
{
    const char *p="hello";
    printf("before foo %s/n",p);
    foo(&p);
    printf("after foo %s/n",p);
    p[1] = 'x';

    return;
}

结论如下:

 

  1. 在foo函数中,可以使main函数中p指向的新的字符串常量。
  2. 在foo函数中,可以使main函数中的p指向NULL。
  3. 在foo函数中,可以使main函数中的p指向由malloc生成的内存块,并可以在main中用free释放,但是会有警告。但是注意,即使在foo中让p指向了由malloc生成的内存块,但是仍旧不能用p[1]='x';这样的语句改变p指向的内容。
  4. 在foo中,不能用(*pp)[1]='x';这样的语句改变p的内容。

      所以,感觉gcc只是根据const的字面的意思对其作了限制,即对于const char*p这样的指针,不管后来p实际指向malloc的内存或者常量的内存,均不能用p[1]='x'这样的语句改变其内容。但是很奇怪,在foo里面,对p指向malloc的内存后,可以用snprintf之类的函数修改其内容。


猜你喜欢

转载自blog.csdn.net/qq_34018578/article/details/73863388