char * ,char ** ,char a[ ] ,char *a[]详解

      C语言中,由于指针的灵活性,所以在代替数组使用,或者混合使用时,往往会引起许多人的迷惑,所以写了这篇博客用来详细区分这几种用法的区别。
      首先,在C语言中,没有真正的字符串类型,可以通过字符数组来表示字符串,因为在数组中,他的地址是连续的,C语言中规定数组名代表数组所在内存地址的首地址,比如str[10],那么str== &str[0];
      比如printf("%s",str);用首地址就可以输出字符串。因为在C语言中字符串常量的本质其实是一个地址。
      比如char *a;   a = "Cprogram",将一个字符串赋值给了一个指针变量,类型不一致啊,但为什么没有错呢?
      因为C语言中编译器会给字符串常量分配一个地址,比如Cprogram这个字符串存储在内存的0x2000,0x2001,0x2002.........
      那么a = "C program"这句话是什么意思?对,就是地址,就是说你把Cprogram看做字符串,但是编译器把他当成地址,就是字符串常量的本质表现是代表他的第一个字符的地址。
      举个例子:
#include  
int main() 

    char*s; 
    s ="hello"; 
   printf("%p\n",s); 
    return0; 

char <wbr>* <wbr>,char <wbr>** <wbr>,char <wbr>a[ <wbr>] <wbr>,char <wbr>*a[]详解

这是输出结果,看到吧,这是字符串的首地址,
所以说你把输出语句换成printf("%s",0x00404000);输出的结果就是字符串hello
C语言中操作字符串是通过它在内存中的存储单元的首地址进行的,这是字符串的本质。
    然后就是char * 和char a[]之间的区别了
   a代表的是字符数组的首地址,s指针保存的是字符串的地址(首地址),每个地址单元里的数据是一个字符,与a数组一致,因此可以使用赋值语句s= a;令指针s指向数组a, But a =s是万万不能的,C语言中数组名可以赋值给指针表示地址,但是不能赋值给数组名,因为它是一个常量类型,所以不能修改。在赋值之后可以通过只用指针名访问数组,举个栗子(敲代码太累了,所以下面都只写了部分代码):
char str[] = "Hello!";
char *s = a;
for (i=0;i<5;i++)
   printf("%c",s[i]);
//也可以使用printf("%c",*s++);
char *与char a[]的本质区别是chara[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*类型,举个栗子:

char *a[]={"Hello","World","gg"}; 

那么问题来了,sizeof(a)是多少呢?6+6+3=15?好像没毛病,NO,NO,NO,前面说了,数组元素类型是一个char*类型,既然是指针类型,那么他就占4个字节,那么它的大小不就是4+4+4=12么,所以sizeof(a)==12;

在举个栗子(举的手疼,咋这么多栗子):

char *a[] ={"Hello","World","gg"};

printf("%p\n%p\n%p\n",a[0],a[1],a[2]);

运行之后可以看到,是三个地址,数组的三个元素保存了三个内存地址,这三个地址代表了三个字符串的首地址,而不是保存的字符串,所以sizeof(a)为12,但是这三个地址不是连续的,因为它是由编译器随机分配的,所以这三个地址并无关联。

看下边代码:

#include 
int main() 

    char *a [] ={"Hello","World","gg"}; 
   printf("%p  %p %p\n",a[0],a[1],a[2]); //数组元素中保存的地址 
   printf("%p  %p %p\n",&a[0],&a[1],&a[2]]);//数组元素单元本身的地址 
    return0; 

运行之后会发现下面输出的是三个连续地址,是元素单元所在地址,每个地址相差四个字节,因为元素是指针变量,每个占用4个字节。

    char **str;char**是二级指针,str保存一级指针char *的地址。

栗子:

 char * a[] = {"Hello","World"};

 char **str = a;

数组a代表数组元素内存单元的首地址,这个地址中又保存着字符串Hello的首地址,这样的话,就可以通过str来对a进行操作。

printf("%s",a[0]);

printf("%s",*a);

printf("%s",*s);

结果一样。

要注意,不能将字符串赋值给二级指针,比如char **str = "HelloWorld";这是错误写法;

因为字符串是char*类型的,而str是char **,两者类型都不一样,那么有人可能会想那这样写是不是就没问题了:char**str;  *str = "HelloWorld";

看起来很对,运行一下吧,诶,运行成功了,But当printf("%s",*str);的时候,崩了,有点迷了,捋一下思路。

首先printf("%s",*str);首先,我们要获得str的地址,然后从这个地址中获得字符串的地址,就是*str,

比如str =0x000001,那么就是说在0x0001中保存了“Hello World”的地址0x001001,就是*str =0x001001

这样输出*str的话,编译器首先找到0x000001,然后找到了0x001001,然后获得了这个字符串,但是*str=“HelloWolrd”的话,str中保存的是什么呢?不知道,野指针出现了,所以崩溃了。所以使用char**str时,需要手动分配一个地址。

char**str;

str = (char **)malloc(sizeof(char**));

*s = "Helloworld"

使用malloc函数手动分配了一个地址,保存helloworld

二级指针其实说白了就是一个指向指针的指针变量,一级指针保存的是指向的数据所在的内存地址,虽然保存的都是地址,但是他们的类型是不一样的。


  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值