char *,char **,char a[ ],char *a[]

1 字符数组

         C语言中规定数组代表数组所在内存位置的首地址,也是 str[0]的地址,即str = &str[0];

         而printf("%s",str); 为什么用首地址就可以输出字符串?因为还有一个关键,在C语言中字符串常量的本质表示其实是一个地址,这是许多初学者比较难理解的问题。

          举例:

          char  *s ;

          s = "China";

          为什么可以把一个字符串赋给一个指针变量?这不是类型不一致吗??这就是上面提到的关键 :C语言中编译器会给字符串常量分配地址,如果 "China", 存储在内存中的 0x3000 0x3001 0x3002 0x3003 0x3004 0x3005 .

          s = "China" ,意思是什么,对了,地址。其实真正的意义是 s ="China" = 0x3000;

          看清楚了吧 ,你把China 看作是字符串,但是编译器把它看作是地址 0x3000,即字符串常量的本质表现是代表它的第一个字符的地址!s = 0x3000;这样写似乎更符合直观的意思。。。

        那么 %s ,它的原理其实也是通过字符串首地址输出字符串,printf("%s ", s);   传给它的其实是s所保存的字符串的地址。

          比如

        #include <stdio.h>

       int main()
       {

         char *s;
         s = "hello";
         printf("%p\n",s);
         return 0;
      }

                          

          

 

      可以看到 s = 0x00422020 ,这也是"China"的首地址

      所以,printf("%s",0x00422020);也是等效的。。

     

       字符数组:

       char  str[10] = "hello";

       前面已经说了,str = &str[0] , 也等于 "hello"的首地址。

       所以printf("%s",str); 本质也是 printf("%s", 地址");

        C语言中操作字符串是通过它在内存中的存储单元的首地址进行的,这是字符串的终极本质!

2  char *  与 char  a[ ];

       char  *s;

       char  a[ ] ;

       前面说到 a代表字符串的首地址,而s 这个指针也保存字符串的地址(其实首地址),即第一个字符的地址,这个地址单元中的数据是一个字符,这也与 s 所指向的 char 一致。因此可以 s = a;,但是不能 a = s;,C语言中数组名可以复制给指针表示地址, 但是却不能赋给给数组名,它是一个常量类型,所以不能修改。。

       char * 与 char a[ ] 的本质区别:

       当定义 char a[10 ]  时,编译器会给数组分配十个单元,每个单元的数据类型为字符。

       而定义 char *s 时,  这是个指针变量,只占四个字节,32位,用来保存一个地址。

       sizeof(a) = 10 ;

       sizeof(s)  = 4

        用一句话来概括,就是 char *s 只是一个保存字符串首地址的指针变量, char a[ ] 是许多连续的内存单元,单元中的元素为char,之所以用 char *能达到char a  [ ] 的效果,还是字符串的本质,地址,即给你一个字符串地址,便可以随心所欲的操所他。但是,char* 和 char a[ ] 的本质属性是不一样的。

    

3  char **  与char  * a[ ] ;

            先看 char  *a [ ]

            由于[ ] 的优先级高于* 所以a先和 [ ]结合,他还是一个数组,数组中的元素才是char * ,前面讲到char * 是一个变量,保存的地址。所以 char *a[ ] = {"China","French","America","German"};

            通过这句可以看到, 数组中的元素是字符串,那么sizeof(a) 是多少呢?有人会想到是五个单词的占内存中的全部字节数 6+7+8+7 = 28,但是其实sizeof(a) = 16!为什么?前面已经说到,字符串常量的本质是地址,a 数组中的元素为char * 指针,指针变量占四个字节,那么四个元素就是16个字节了!

            看一下实例:

            #include <stdio.h>

   int main()
   {
    char *a [ ] = {"China","French","America","German"};
    printf("%p %p %p %p\n",a[0],a[1],a[2],a[3]);

    return 0;
   }

    

      可以看到数组中的四个元素保存了四个内存地址,这四个地址中就代表了四个字符串的首地址,而不是字符串本身。因此sizeof(a)当然是16了。。

      注意:这四个地址是不连续的,它是编译器为"China","French","America","German" 分配的内存空间的地址, 所以,四个地址没有关联。


         #include <stdio.h>

   int main()
   {
   char *a [ ] = {"China","French","America","German"};

           printf("%p %p %p %p\n",a[0],a[1],a[2],a[3]); //数组元素中保存的地址
   printf("%p %p %p %p\n",&a[0],&a[1],&a[2],&a[3]);//数组元素单元本身的地址

   return 0;
   }

          

      可以看到 0012FF38 0012FF3C 0012FF40 0012FF44,这四个是元素单元所在的地址,每个地址相差四个字节,这是由于每个元素是一个指针变量占四个字节!!!

      

再看char **s

       char **为二级指针, s保存一级指针 char *的地址,关于二级指针就在这里不详细讨论了 ,简单的说一下二级指针的易错点。 

易错点1:

       举例:

       char *a [ ] = {"China","French","America","German"};

       char **s =   a;

     为什么能把 a赋给s,因为数组名a代表数组元素内存单元的首地址,即 a = &a[0] = 0012FF38;而 0x12FF38即 a[0]中保存的又是 00422FB8,这个地址, 00422FB8为字符串"China"的首地址。即 *s = 00422FB8 = "China";  这样便可以通过s 操作 a 中的数据!

即:

      printf("%s",*s);

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

      printf("%s",*a);

      都是一样的!!!

      但还是要注意:不能a = s,前面已经说到,a 是一个常量!

易错点2:

      char **s = "hello world";

      这样是错误的,因为  s 的类型是 char **  而 "hello world "的类型是 char *

       虽然都是地址, 但是指向的类型不一样,因此,不能这样用。从其本质来分析,"hello world"代表一个地址,比如0x003001,这个地址中的内容是 'h',为 char 型,而 s 也保存一个地址 ,这个地址中的内容(*s) 是char *,是一个指针类型,所以两者类型是不一样的。

  如果是这样呢?
  char  **s;

       *s = "hello world";

       貌似是合理的,编译也没有问题,但是 printf("%s",*s),就会崩溃,why??

      咱来慢慢推敲一下。。

       printf("%s",*s); 时,首先得有s 保存的地址,再在这个地址中找到 char *  的地址,即*s;

      举例:

       s = 0x1000;

      在0x1000所在的内存单元中保存了"hello world"的地址 0x003001 , *s = 0x003001;

      这样printf("%s",*s);

      这样会先找到 0x1000,然后找到0x003001;

      如果直接 char  **s;

      *s = "hello world";

       s 变量中保存的是一个无效随机不可用的地址, 谁也不知道它指向哪里。。。。,*s 操作会崩溃。。

       所以用 char **s 时,要给它分配一个内存地址。

      char  **s ;

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

      *s =  "hello world";

      这样 s 给分配了了一个可用的地址,比如 s = 0x412f;

      然后在 0x412f所在的内存中的位置,保存 "hello world"的值。。

    再如:

    #include  <stdio.h>

   void  buf( char **s)

    {

           *s = "message";

    }

    int main()

     {

        char *s ;

        buf(&s);

        printf("%s\n",s);

     }

    二级指针的简单用法,说白了,二级指针保存的是一级指针的地址,它的类型是指针变量,而一级指针保存的是指向数据所在的内存单元的地址,虽然都是地址,但是类型是不一样的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值