C语言注释符号一本道来

符号与注释.png

注释符号

一个好的注释

akari.png

好的注释(摘自网络)

  • 注释应该准确易懂,防止二义性,错误的注释有害
  • 注释是对代码的提示,避免臃肿和喧宾夺主
  • 一目了然的代码避免加注释
  • 不要用缩写来注释代码,这样可能会产生误解
  • 注释用于阐述原因而不是用来描述程序的运行过程
  • 不要给用户起奇怪的名字。否则像虾米工程师一样

exp:初探注释规则

#include <stdio.h>

int main()
{
    int/*...*/i;//编译器对注释的处理不是简单的删除,而是用空格来代替
    char* s = "abcdefgh      //hijklmn";//注释符号是不能在双引号之间的
    
    //Is it a \//'\'反斜杠可以当作换行符号
    valid comment?
    
    in/*...*/t i;
    
    return 0;
}

结论

  • 编译器对注释的处理不是简单的删除,而是用空格来代替
  • 注释符号是不能在双引号之间的
  • ''反斜杠可以当作换行符号

一个不安宁的反斜杠(接续符号和转义符号)

接续符号:\(反斜杠)

最佳实例

#include\
<stdio.h>
int main(){
        printf\
("hello");
}

编译预处理后

int main(){
 printf("hello");
}

很明显可以看出来,编译预处理的时候将接续符去掉,将下一行补上来。这种用法常用在宏函数

接续符号的作用

  • 编译器会将反斜杠剔除,跟在反斜杠后面的字符自动解到前一行
  • 在接续单词时,反斜杠之后不能有空格,反斜杠的下一行之前也不能有空格
  • 接续符号适合在宏定义代码块时使用

举个栗子

#include<stdio.h>
void swap(int a,int b)
{
        int temp=a;    
    a=b;        
    b=temp;        
}
//下面就是宏函数
#define SWAP(a,b)  \
{                  \
    int temp=a;    \
    a=b;           \
    b=temp;        \
}
void main()
{
    int a=10,b=20;
    SWAP(a,b);
    printf("a=%d\nb=%d\n",a,b);
}

转义符号

转义符号用来表示无回显的符号

转义符号.png

小结

  • C语言中的反斜杠同时具有接续符号和转义符号的作用
  • 当反斜杠作为接续符号使用时可直接出现在程序中
  • 当反斜杠当转义符号使用时需出现在字符或字符串中

单身狗与双生人(单引号和双引号)

最佳示例

#include<stdio.h>
void main()
{
    char * p1=1;      //指向内存地址为一的位置(野指针)
    char * p2='1';    //指向1的ASCALL码的位置也就是内存中49为 (野指针)
    char * p3="1";    //真正指向一字符串的位置
        printf('\n');//printf的参数是字符类型的首地址指针,也就是调用\n所在位置的地址的指针
}

从上面的注释和例子可以得到这样几个结论

  • 本质上单引号括起来的一个字符代表整数,就是ASCALL码
  • 双引号括起来的字符代表一个指针
  • C编译器接收字符和字符串的比较,会有warning
  • C编译器容许字符串对字符变量赋值,但是没意义

逻辑运算符使用分析

&& 和||

最佳示例

#include<stdio.h>
void main()
{
    int i=0;
    int j=0;
    if(++i>0 || ++j>0)
    {
        printf("%d\n",i);
        printf("%d\n",j);
    }
}

输出的结果是1,0.下面来解释原因

程序的短路规则

  • ||从左到右开始计算,当遇到为真的条件时停止计算,整个表达式为真:所有条件为假时才为假
    • 这道题很明显的符合这个条件,程序运行完++i的时候i>0成立,那么条件的后半段不会被执行
  • &&从左到右开始计算,当遇到为假的时候停止计算,整个式子为假;所有条件都为假的时候才为假

!

最佳示例

#include<stdio.h>
void main()
{
    printf("%d\n",!0);
    printf("%d\n",!1);
    printf("%d\n",!100);
    printf("%d\n",!-1000);
}

答案 1,0,0,0

结论:

C语言中的逻辑“!”只认得“0”,只知道0取非为1,若果不为0,结果都为0

三目运算符

最佳示例

假设有a,b三个变量,如果a>b,那么给a赋值为3。

我脑中第一个闪过的程序是a<b? &a=3:&b=3;然后emmmmmm,报错,于是,就觉得C语言的三目运算符有点搞头。查了一些blog才知道,真正的写法是*(a<b? &a:&b)=3;

#include<stdio.h>
void main()
{
    int a=0;
    int b=2;
    int c=1;
    *(a<b? &a:&b)=3;
    printf("%d\n",a);
    printf("%d\n",b);
    printf("%d\n",c);
}

总结

不要被其他语言带翻车


位运算符号分析

位运算种类

位运算.png

运算法则(和数学一样)

  • 结合律
  • 交换律

防错准则

  • 避免位运算符号,逻辑运算符号和数学运算符号同时出现在一个表达式中
  • 当位运算,逻辑运算符和数学运算符号同时出现的时候最好加括号来表达计算的次序(加减法的优先级高于位运算)

运算小技巧

技巧一

  • 左移n位相当于乘以2的n次方,但是效率比数学运算符高
  • 右移n位相当于除以2的n次方

最佳示例

使用左移的方法

#include<stdio.h>
#include<time.h>
void main(){
        int h,e;
        h=clock();
        printf("%d\n",256>>4);
        printf("%d\n",256>>4);
        printf("%d\n",256>>4);
        printf("%d\n",256>>4);
        printf("%d\n",256>>4);
        printf("%d\n",256>>4);
        printf("%d\n",256>>4);
        printf("%d\n",256>>4);
        printf("%d\n",256>>4);
        printf("%d\n",256>>4);
        e=clock();
        printf("%d毫秒\n",e-h);
}

结果113毫秒

使用除法

#include<stdio.h>
#include<time.h>
void main(){
        int h,e;
        h=clock();
        printf("%d\n",256/16);
        printf("%d\n",256/16);
        printf("%d\n",256/16);
        printf("%d\n",256/16);
        printf("%d\n",256/16);
        printf("%d\n",256/16);
        printf("%d\n",256/16);
        printf("%d\n",256/16);
        printf("%d\n",256/16);
        printf("%d\n",256/16);
        e=clock();
        printf("%d毫秒\n",e-h);
}

结果141毫秒

结论

我这里只用十次除法。虽然看似毫秒只差,但是一旦到项目中运算量大的时候,失之毫秒,差之千秒,至于原因,是因为计算机是二进制的玩意。它似乎更喜欢处理位运算

技巧二

最佳示例


#include<stdio.h>
#define SWAP1(A,B)\
{          \
int temp=A;\
A=B;        \
B=temp;      \
}
#define SWAP2(a,b)\
{\
a=a+b;\
b=a-b;\
a=a-b;\
}
#define SWAP3(a,b)\
{\
a=a^b;\
b=a^b;\
a=a^b;\
}
int main()
{
    int a=10,b=20;
    SWAP1(a,b);
    SWAP2(a,b);
    SWAP3(a,b);
    printf("a=%d,b=%d\n",a,b);
    
    
}

一共三种方法进行位置交换

优缺点表

方法 优点 缺点
SWAP1 无论什么类型的都可以 效率十分的底下
SWAP2 效率相对较高 容易溢出,效率一般,类型只能是整型
SWAP3 效率非常高 类型只能是整型,推荐使用

最佳实战

题目:2,3,5,7,2,2,2,5,3,7,1,1,1找出基数个的数字(也就是1)

思路:用亦或的方法最好,因为偶数个亦或等于零,所以,所有的数字亦或的结果剩下的数字就是我们要找的数字

#include<stdio.h>
#define DIM(a)\
(sizeof(a)/sizeof(*a))
void main()
{
    int a[]={2,3,5,7,2,2,2,5,3,7,1,1,1};
    int i=0;
    int answer=0;
    for(i=0;i<DIM(a);i++)
    {
        answer=a[i]^answer;
    }
    printf("the result is %d\n",answer);
} 

注意

如果移位超过他最大的位数,那么结果为0,例如:1<<32的结果为0

移动位数为负数的结果是0,例如:1<<-1的结果为0


++,- -操作符号的分析(头疼地带)

int i=3;
(++i)+(++i)+(++i)=?

这里有两种解释:

  1. ++i是平等的一共有3个,需要加三次,所以是18(3x6)
  2. 先处理两个,然后再加后一个里面的内容,前两个加完为10,再加一个的话就为16(如果是Linux开发是这种,准没错。在gccg++测试通过)

逗号表达式如何计算

规则:从左算到右顺序求值,最后一个表达式的值就是逗号表达式的值

最佳示例

int x=4;
int k=(++i,i++,i+10);

结果16,没什么好说的


如何检验程序是否正确?贪心法

  • 编译器处理的每个符号应该尽可能多的包含字符
  • 编译器以从左到右的顺序一个一个尽可能多的读入字符
  • 当即将读入的字符不可能和已读入的字符组成合法的符号为止

分析++i+++i

第一步:++i,到第二步++i+,到第三步++i++,很显然如果用贪心法分析,程序是错的 .事实证明程序确实是错的.


优先级和类型转换分析

C语言中的优先级(常产生的错误)

优先级转化


优先级.png
#include<stdio.h>
#include<malloc.h>
typedef struct _dome{
    int * pInt;
    float f;
} DOME;
int func(int i,int j)
{
    return (i&j !=0);//因为比较符号的优先级高于按位符号所以,这里的输出结果为先判断m!=0然后,再按位与
}
void main()
{
    DOME *pD=(DOME*)malloc(sizeof(DOME));
    int *p[5];//这里相当于int* p[5];
    int *f();//这里相当于 int* f();
    int i=0;
    i=1,2;//逗号表达式应当加括号
    *pD.f=1;//这里相当于pD.f=1后的指针
    free(pD);
    
}

注释里把需要解释的都注释好了,一看就懂

C语言隐式类型转换

隐式优先级表


隐式优先级.png
  • 算术运算表达式中,低类型转换为高类型
short c=1;
char b=0;
c+b 的类型?

c+b为short类型

  • 赋值表达式中,表达式的值转换为左边变量的类型,例如

    • short a=1;
      char b=2;
      a=b;//这里的b会隐式转化为short类型
      
  • 函数调用时,实参转化为形式参数的类型

  • 函数返回值,return表达式转化为返回值的类型

最佳示例

#include<stdio.h>
void main()
{
    int i=-2;
    unsigned int j=1;
    if((i+j)>0)//看上面的图片可以知道int类型先变成unsigned类型进行计算
    {
        printf("i+j>0");
    }else
    {
        printf("<0");
    }
    printf("%d",i+j);
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,596评论 18 139
  • “国际 C 语言乱码大赛( IOCCC)”,下面这个例子就是网上广为流传的一个经典作品: 2.1 注释符号 2.1...
    HavenXie阅读 1,204评论 0 3
  • FreeCodeCamp - Basic JavaScript 写在前面: 我曾经在进谷前刷过这一套题,不过当时只...
    付林恒阅读 16,428评论 5 28
  • JavaScript 注释语句操作 注释的代码块在JavaScript之中是不会运行的。注释是一个非常好的方式让你...
    followyounger1阅读 7,940评论 0 2
  • 今夜苹果很贵 比苹果更贵的是人心 有人因狂欢而失落 如一场落幕的夜戏 有人因苹果而陷入落寞 如平静的湖水散开涟漪 ...
    杨昊田阅读 253评论 6 10