C语言中,由于指针的灵活性,所以在代替数组使用,或者混合使用时,往往会引起许多人的迷惑,所以写了这篇博客用来详细区分这几种用法的区别。
首先,在C语言中,没有真正的字符串类型,可以通过字符数组来表示字符串,因为在数组中,他的地址是连续的,C语言中规定数组名代表数组所在内存地址的首地址,比如str[10],那么str == &str[0];
比如printf("%s",str);用首地址就可以输出字符串。因为在C语言中字符串常量的本质其实是一个地址。
比如char *a; a = "C program",将一个字符串赋值给了一个指针变量,类型不一致啊,但为什么没有错呢?
因为C语言中编译器会给字符串常量分配一个地址,比如C program这个字符串存储在内存的0x2000,0x2001,0x2002.........
那么a = "C program"这句话是什么意思?对,就是地址,就是说你把C program看做字符串,但是编译器把他当成地址,就是字符串常量的本质表现是代表他的第一个字符的地址。
举个例子:
这是输出结果,看到吧,这是字符串的首地址,
所以说你把输出语句换成printf("%s",0x00404000);输出的结果就是字符串hello
C语言中操作字符串是通过它在内存中的存储单元的首地址进行的,这是字符串的本质。
然后就是char * 和char a[]之间的区别了
a代表的是字符数组的首地址,s指针保存的是字符串的地址(首地址),每个地址单元里的数据是一个字符,与a数组一致,因此可以使用赋值语句s = a;令指针s指向数组a,
But a = s是万万不能的,C语言中数组名可以赋值给指针表示地址,但是不能赋值给数组名,因为它是一个常量类型,所以不能修改。在赋值之后可以通过只用指针名访问数组,举个栗子(敲代码太累了,所以下面都只写了部分代码):
char *与char a[]的本质区别是char a[10],编译器会直接给数组分配十个char类型大小的单元,每个单元保存一个字符,而char *s时,定义了一个指针变量,它只占4个字节,保存一个地址,所以sizeof(a)==10 True sizeof(s) == 4 True
用一句话来概括,就是 char *s 只是一个保存字符串首地址的指针变量, char a[ ] 是许多连续的内存单元,单元中的元素为char ,之所以用 char *能达到
char a [ ] 的效果,还是字符串的本质,地址,即给你一个字符串地址,便可以随心所欲的操所他。但是, char* 和 char a[ ] 的本质属性是不一样的。
最后,来看最难理解的部分,char **和char * a[]
先看char * a[],[]的优先级大于*,所以a先和[]结合,所以首先他还是一个数组,由于前面还有个*,所以数组中的元素是char *类型,举个栗子:
那么问题来了,sizeof(a)是多少呢?6+6+3=15?好像没毛病,NO,NO,NO,前面说了,数组元素类型是一个char*类型,既然是指针类型,那么他就占4个字节,那么它的大小不就是4+4+4=12么,所以sizeof(a)==12;
在举个栗子(举的手疼,咋这么多栗子):
运行之后可以看到,是三个地址,数组的三个元素保存了三个内存地址,这三个地址代表了三个字符串的首地址,而不是保存的字符串,所以sizeof(a)为12,但是这三个地址不是连续的,因为它是由编译器随机分配的,所以这三个地址并无关联。
看下边代码:
运行之后会发现下面输出的是三个连续地址,是元素单元所在地址,每个地址相差四个字节,因为元素是指针变量,每个占用4个字节。
char **str;char**是二级指针,str保存一级指针char *的地址。
栗子:
数组a代表数组元素内存单元的首地址,这个地址中又保存着字符串Hello的首地址,这样的话,就可以通过str来对a进行操作。
结果一样。
要注意,不能将字符串赋值给二级指针,比如char **str = "Hello World";这是错误写法;
因为字符串是char *类型的,而str是char **,两者类型都不一样,那么有人可能会想那这样写是不是就没问题了:char **str; *str = "Hello World";
看起来很对,运行一下吧,诶,运行成功了,But当printf("%s",*str);的时候,崩了,有点迷了,捋一下思路。
首先printf("%s",*str); 首先,我们要获得str的地址,然后从这个地址中获得字符串的地址,就是*str,
比如str = 0x000001,那么就是说在0x0001中保存了“Hello World”的地址0x001001,就是*str = 0x001001
这样输出*str的话,编译器首先找到0x000001,然后找到了0x001001,然后获得了这个字符串,但是 *str=“Hello Wolrd”的话,str中保存的是什么呢?不知道,野指针出现了,所以崩溃了。所以使用char**str时,需要手动分配一个地址。
使用malloc函数手动分配了一个地址,保存hello world
二级指针其实说白了就是一个指向指针的指针变量,一级指针保存的是指向的数据所在的内存地址,虽然保存的都是地址,但是他们的类型是不一样的。