C专家编程 精编之一

本文摘自《C专家编程》前三章,详细解析了C语言中指针、声明和复杂表达式的理解难点,包括:指针与声明的复杂性、const与指针的关系、函数指针、数组与指针的关系、sizeof运算符的应用、switch语句的特性、预处理器的陷阱等。通过对实例的分析,帮助读者深入理解C语言的底层机制和常见错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C专家编程  精编之一     第一章~第三章

谄笑 C的复杂之处 在于它的指针 ,但是比其指针更为复杂的是它的声明 !!! 赞

能看懂它们的意思 吗?疑问

apple=sizeof(int)*p  ;   apple=sizeof * p;

j= (char (*)[20])malloc(20);

int   const * grape; 与   int * const grape; 的区别 

typedef void (*ptr_to_func)(int);

void (*signal(int sig,void (*func)(int )))(int );   大哭

几个样例:
        一:char *a; const char *b;   a=b;//出现警告.         why?
        二: const int two =2;
            switch(i)
             {
              case 1:printf("case 1 !  /n");
              case two :printf("case 2/n");
              }
            编译出错,说明了.....?
       三:switch(){..}中 default改成 defau1t (无心之过,或其它标签如defavlt,dafault..)都编译通过 .  why?
       四: apple=sizeof(int)*p  ;   apple=sizeof * p;    //是什么意思?   另外, y=sizeof x; 能编译通过吗?
       五:  j= (char (*)[20])malloc(20);                     //怎么样?
       六:  result=*x/*y ;     //出错?why   ?   
             z=y+++x;   即为: z=y++ +x;    但z=y+ + +x;    z=y+ ++x;   呢?         
      七:  const   int * grape; 
             int   const * grape;
             int * const grape;       //有什么区别?
八:  int (* fun())()        
             int  (* fun())[]        
             int (* funp[])()        //各是什么意思?
九:  void (*signal(int sig,void (*func)(int )))(int ); //什么意思??
       十:  typedef void (*ptr_to_func)(int);                //这个用法,你会吗?
       十一:struct foo{int foo;}foo;  // 合法! 那么,sizeof(foo)又表示哪一个foo呢?
       .........
  以上几个例子是这篇文章的主要内容,是我根据 C专家编程 前三章 的主要内容整理的.
  如果对上面的问题很清楚,那么就没有必要看下去,
  如果对C一点都不了解,也没有必要看下去.
  如果对C非常感兴趣,同样也没有必要看下去,直接看书吧...
问题一:实参char * s 与形参 const char *p是相容的,但是为什么  实参 char * *argv 与形参 const char **p实际上不能相容?
        例:
            foo(const char **p){ }
            main(int argc,char **argv)
            {
               foo(argv);
            }
  //产生warning:argument is incompatible with prototype 即  警告:参数与原型不匹配
     问题产生: 实参 char *s 与 形参const char *p应该是相容的,那么为什么  实参 char * *argv 与形参 const char **p实际上不能相容?
       答案途径:  ANSI C 标准.
     6.3.2.2: 每个实参都应该具有自己的类型.这样它的值就可以赋值给与它所对应的形参类型的对象(该对象的类型不能含有限定符).      也就是说参数传递过程类似于赋值.
     //即:const char **类型的对象可以赋值给一个类型为 char **的值,否则..... //why?
      赋值规则: 6.3.16.1:
     要使上面的赋值合法,必须满足下列条件:
     两个操作数都是指向有限定符或无限定符的相容类型的指针,左边指针所指向的类型必须具有右边指针所指向类型的全部限定符. 
   //即指向的类型相容且左有右全部限定符. 
  例:char *a;
      const char *b;
      若b=a;       //可行;
      若a=b;       //不可行.警告.
    6.1.2.5说明:char float * 类型并不是一个有限定符的类型------它的类型是"指向一个具有const限定符的char类型的指针",也就是说const限定符是修饰指针所指向的类型,而不是指针本身.  //参见:问题const
    因此,由于char **和const char **都是没有限定行的指针类型,但它们所指向的类型不一样(前者指向char * ,后者指向 const char *).故,它们是不相容的.         
    下面更亲切的解释:
             左操作数:   p-------->Foo (char *)------------>const char ;
             右操作数:   argv---->Baz (char *)------------>char ;
         若:  p=argv;
             则:Foo和Baz所指向的类型是相容的,而且它们本身都没有限定符,所以符合标准的约束条件,两之间赋值合法.
      但是,Foo和Baz并不相容.故  p=argv不合法. //p19~p20页,再看几遍!!!
问题2:关于char ,int ,long int ,float ,double,long double等计算时的转换.
注意:unsigned类型!
尽量不要使用unsigned类型,以免造成边界问题!!!  -1<1000    返回 0
问题3:
  #define TOTAL_ELEMENTS   (sizeof(array)/sizeof(array[0]))   
而不是:
#define TOTAL_ELEMENTs   (sizeof(array)/sizeof(array(int))
原因:第一个可移植性强.
问题4:NUL  与 NULL
NUL:用于结束一个ASC字符串;
NULL:用于指向空指针.
问题5:关于switch
         switch的一个问题是它内部的任何语句都可以加上标签,并在执行时跳转到那里.
         并且所有的标签都是可选的,如:若把default打成  defau1t 它能顺利通过编译,不显示错误.       
         另外,在C中,const并不真正表示常量.如:
          const int two =2;
          switch(i)
           {
              case 1:printf("case 1 !  /n");
              case two:printf("case 2/n");
     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值