写注释使我们代码的一个好的优点,注释我们需要简而精,注释要做到:简单、一动,不存在二义性,简单的代码不需要加上注释;
C语言的注释有两种,一种是 /* */、一种是 //
#include <stdio.h>
int main()
{
int /* */ i = 10;//正确
char* s = "abcdef //ghigk";//正确
//Is it a\
valid comment? //正确,反斜杠\表示续航符
in/* */t j = 20;//错误
return 0;
}
注意1:注释本质是被替换成空格的
例如:
这种写法就是正确的,我们从而也可以知道# 与 define之间是可以带空格的;
注意2:c风格的注释是无法嵌套的
这样编译器会报错,/* 总会与离他最近的 */匹配
我们本意是要拿x除以指向p里面的值,我们测试一下
int x = 10;
int y = 0;
int z = 5;
int* p = &z;
y = x / * p;
printf("%d\n", y);
如果我们要写成y = x /* p;
这样编译器是会把 /* 识别成注释的;这种情况我们应写成y = x / * p;
或者y = x/(*p);
;
/与*之间没有空格,编译器就会把/*认为成是注释的开始
我们都知道,有些软件会分为会员和非会员,而非会员的部分功能是无法使用的,那么在设计程序时,我们需要写两部分吗?肯定是不需要的,我们只需要将那些会员功能给隐藏就可以了;这里就会用到条件编译,当达到某些条件时,才会执行这些代码!
例如:
#include <stdio.h>
int main()
{
//条件编译
#if 0 //0就是不执行,非0就是执行
printf("for test1\n");
printf("for test2\n");
#endif
//基于条件编译,我们还可以这样写,但是不推荐这样写
if (0)
{
printf("for test1\n");
printf("for test2\n");
}
return 0;
}
//1.\作为续行符
int a = 1;
int b = 2;
int c = 3;
if (a == 1 && \
b == 2 && \
c == 3) {
printf("hello world\n");
}
//2.\作为转义符
printf("h\tello wor\nld!\n");
这里:\t 相当于 table键;\n表示换行
注意:\作为续行符时,后面不可以加空格,否则会报错,前面可以有空格
回车(\r)是将光标移动到该行的开始,换行(\n)就是将光标移动到下一行; 回车加上换行才是我们理解上的回车(键盘上的enter键)
我们可以实现一个倒计时:
#include <stdio.h>
#include <Windows.h>
int main()
{
int i = 10;
while (i >= 0)
{
Sleep(1000);
printf("%2d\r", i--);// \r表示回车,移动到该行的最开始
}
return 0;
}
单引号表示字符,而双引号表示字符串
printf("%d\n", sizeof(1));//4
printf("%d\n", sizeof('1'));//4
printf("%d\n", sizeof("1"));//2,要加上字符串结束标志
char c = '1';
printf("%d\n", sizeof(c));//1
C99标准的规定,'a’叫做整形常量字符,被看成int型,所以sizeof(‘1’)是4个字节大小,而char类型是占用一个字节的空间;char c = 'abcd'; printf("%c\n", c);//d
所以这样的代码是正确的,但是单引号里面最多有四个字符,因为’ '看成int型,我们在最开始就说过先开辟好空间,再把变量存放进去,所以高位abc就被舍弃了,字符c里面只存储了一个字符d!
特殊情况:
printf("%d\n", sizeof(''));//报错
printf("%d\n", sizeof(""));//1,只有一个字符串结束标志\0
这里面的基础语法就不说了,我么只要知道逻辑运算符具有短路的运算规则;就是有一个条件不满足时,后面的条件就不再看了;
demo:
#include <stdio.h>
int show()
{
printf("you can see me!\n");
return 1;
}
int main()
{
int a = 0;
scanf("%d", &a);
a == 10 && show();//当输入的a值不是10时,后面的show函数自动不执行
return 0;
}
按位与(&)、按位或(|)、按位异或(^)都是逐比特位进行位运算的!
我们主要来理解一下按位异或;
按位异或:逐比特位比较,相同为0,相异为1
按位异或满足交换律与结合律;例如:看一个现象
printf("%d\n", 5 ^ 4 ^ 5);//4
printf("%d\n", 5 ^ 5 ^ 4);//4
printf("%d\n", 5 ^ (5 ^ 4));//4
根据按位异或满足交换律与结合律,我们可以通过这个规律来实现两个数交换(不使用中间变量)
#include <stdio.h>
int main()
{
//方法1:有整形溢出的风险
int a = 10;
int b = 20;
printf("before: a = %d, b = %d\n", a, b);
a = a + b;
b = a - b;
a = a - b;
printf("after: a = %d, b = %d\n", a, b);
//方法2:按位异或
a = 10, b = 20;
printf("before: a = %d, b = %d\n", a, b);
a ^= b;
b ^= a;
a ^= b;
printf("after: a = %d, b = %d\n", a, b);
return 0;
}
位操作,指定位修改比特位,我们用宏来定义;
#include <stdio.h>
#define SETBIT(x, n) ((x) |= (1 << (n - 1))) //指定比特位为1,用按位或
#define CLRBIT(x, n) ((x) &= (~(1 << (n - 1)))) //指定比特位为0,用按位与(要加上取反符号)
//输出数字的二进制
void ShowBit(int x)
{
int num = sizeof(x) * 8 - 1;
while (num >= 0)
{
if (x & (1 << num)) printf("1 ");
else printf("0 ");
num--;
}
puts("");
}
int main()
{
int x = 0;
//1.设置指定比特位为1
SETBIT(x, 5);
ShowBit(x);
//2.设置指定比特位为0
int y = 0xFFFF;
CLRBIT(y, 5);
ShowBit(y);
return 0;
}
先看现象:
char c = 0;
printf("%d\n", sizeof(c));//1
printf("%d\n", sizeof(~c));//4
printf("%d\n", sizeof(c << 1));//4
printf("%d\n", sizeof(c >> 1));//4
无论什么运算符,都是需要计算机运算的,而计算机只有CPU具有运算能力;但数据都是在内存当中,所以计算之前都必须要从内存中拿取数据放到CPU中(CPU中的寄存器中);一般寄存器的位数都是32位,而一个char类型只占一个字符,需要整型提升!!!
但是,有一个特例,在vs中:printf("%d\n", sizeof(!c));//1
只占一个字节,但在Linux中却占用四个字节,编译器有自己的理解;
注意:0x01 << 2 + 3是多少?
printf("%d\n", 0x01 << 2 + 3);//32
printf("%d\n", 0x01 << (2 + 3));//32
printf("%d\n", (0x01 << 2) + 3);//7
+的优先级比<<高
以++为例:基础语法我们都了解,a++是先使用后++,++a是先++后使用;
如果是b = ++a;
是先++在使用(赋值给b),但是如果是直接++a;
呢,那怎么先使用呢?其实,不管会不会有值来接受这个值,我们都是将a放到寄存器中来+1操作,我们来看一下汇编代码:
总结:a++完整的含义是先使用,在自增;如果没有变量接收,那么直接自增,就是读取进寄存器,就没有然后了
来看一个例子:
int i = 1;
int j = (++i) + (++i) + (++i);
printf("%d\n", j);
上面的答案应该是多少呢?C语言与gcc的答案还不太一样,++i是先自增在使用,gcc中先计算前面两个++i,也就是i先自增为2,然后第二个i再自增为3,i这时候在使用都是3,3 + 3 = 6,最后一个i在先自增,为4,在与前两个相加,也就是 3 + 3 + 4 = 10;C语言中,是三个++i同时先自增,最后i变成4,然后 4 + 4 + 4 = 12;