转载前注明出处,欢迎转载分享
C Code
C Code
C Code
C Code
C Code
C Code
C Code
C Code
C Code
接续符:
\可以作为
接续符和
转义符,当作为接续符(\)使用时:
- 编译器会将反斜杠剔除,跟在反斜杠后面的字符自动解到前一行
- 在接续单词时,反斜杠之后不能有空格,反斜杠的下一行之前也不能有空格
- 接续符适合在定义宏代码块时使用
来看如下代码:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
#include #define { } void { } int { } |
接续符的使用有利有弊,如果在代码中随意使用接续符,会使得代码变得非常混乱难读,但如果使用恰当(如上述代码),则会让代码变得非常小清新-。-
单引号和双引号:
来看下面的程序:
1
2 3 4 5 6 7 8 9 10 11 12 13 |
#include int { } |
上述程序中:
p1 = 1; 意思是让p1指向内存地址为1的地方
p2 = '1'; 意思是让p2指向内存地址为49
p3 = "1"; 意思是让p3指向字符串“1”所对应的地址。
在操作系统里,低位的地址一般保留起来给操作系统用的。(
从物理内存地址而言,操作系统一般都是放在低地址。从虚拟内存地址而言,操作系统一般都是放在高地址)这里所取的地址为物理地址。所以打印p1,p2的时候无法访问,即
段错误(错误的访问了其他内存地址段)。
1
|
printf(char |
同样的对于:
1
|
printf('\n');
|
即就是对第一个参数进行赋值,代码如下:
1
|
format |
及指针指向了内存地址为10(\n的ASCII码值),为较低内存地址段,所以也会无法访问,产生段错误。
从编译器的角度,它认为p1,p2,p3的赋值是正确的,但是会有疑惑,因为用的人非常少,所以编译器会给出warning,但不会报错,所以p1,p2,p3的赋值是可以编译通过的,但随后也产生了段错误。
单引号和双引号的区别在于:
- 'a'表示字符常量,在内存中占1个字节,'a'+1表示'a'的ASCII码加1,结果为'b'
- “a”表示字符串常量,在内存中占2个字节,“a”+1表示指针运算,结果指向“a”结束符'\0'
看看如下错误代码:
1
2 3 4 5 6 7 8 9 10 11 |
#include int { } |
该代码想要表达的意思我们都懂,但是犯了很低级的错误。
char c = " ";
这行代码的意思是将存放字符串“ ”的首地址赋值给c,比如存放“”的首地址为32位的0xAABBCCDD,但是赋值给c时因为c仅有8位地址,所以会产生截断,及c =0xDD,也就是说定义的c为字符类型怎么能用双引号呢?该程序将所有双引号改为单引号后即正确。
对于单引号与双引号的总结:
- 本质上单引号括起来的一个字符代表整数。
- 双引号括起来的字符代表一个指针
- C编译器接收字符和字符串的比较,可意义是错误的
- C编译器允许字符串对字符变量赋值,其意义是可笑的
三目运算符(a?b:c):
三目运算符(a?b:c)可以作为
逻辑运算符的载体
规则:当a的值为真时,返回b的值;否则返回c的值
看如下代码:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include int { } |
上述为错误代码,如果你认为结果输出的是:
3,2,1那就错了。仔细分析一下这条语句:
1
|
(a |
三目运算符把a的值作为了左值,这明显是错误的,当然我们还是可以通过对其修改来达到想要的目的,而且还提升了编程B格,代码如下:
1
|
*(a |
这条语句巧妙运用了指针的方法,其实也等同于下面的代码:
1
2 |
p *p |
位运算的移位运算符(<<,>>)小技巧:
- 右移n位相当于乘以2的n次方,但效率比数学运算符高。
- 右移n位相当于除以2的n次方,但效率比数学运算符高。
交换运算:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#define { } #define { } #define { } |
这样的写法就是对上面所写的接续符的运用,比较这三种交换运算,有如下特点:
第一种交换相比另外两种交换,
多定义了一个临时变量进而实现交换。
第二种交换方式不细说了,但是第二种交换有一定的优点和缺点,
优点在于其交换只用到了两个变量,不需要再申请一个临时存放变量,但
缺点在于当执行a= a +b;时,如果a和b的值非常大,两个变量相加则可能产生越界,所以第二种交换在特定条件下不会得到我们预期的结果。
第三种交换是通过异或实现交换,先将a = a ^b;第二条语句即b = a ^ b ^ b;就是让b = a; 第三条语句是a = a ^ b ^ a;即a = b;进而产生交换,这种按位运算在C中运算效率非常高,我们之前一直使用第一种交换,是因为第一种交换相比第三种也有其优势,第三种交换不足在于它
仅适用于整型数,但不会产生像第二种交换那样所产生的越界问题,第三种交换方法是我们真正学习C应该掌握的内容。
面试题详解:
有一个数列2,3,5,7,2,2,2,5,3,7,1,1,1,其中的自然数都是以偶数的形式出现,只有一个自然数出现次数为奇数次,编写程序找出这个自然数。
思路1:给数列排序,遍历并且计数,判断计数是否能被2整除即可。(缺点:排序耗时)
思路2:申请数组a[],数组b[],遍历利用b[a[i]]++判断b数组奇偶性来确认出现的次数,类似桶排序原理。(换来时间,耗费空间)
思路3(推荐):将数列每个数取异或位运算,及2^3^5^7^2^2^2^5^3^7^1^1^1,最终为奇数的数即可找出。(省时间,省空间)
代码如下:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#include #define int { } |
++,--操作符
1
2 3 4 5 6 7 8 9 10 11 |
#include int { } |
看上述代码后你能猜出输出结果是多少吗?
1
|
int |
对于编译器来说,不同的编译器给出不同的值,
有些编译器认为先将这三个i相加,然后执行三次++操作,结果为9;
另一些编译器(gcc和g++下)认为先结合前两项即i+i,然后执行两次++操作,再与第三个i结合,执行一次++操作,结果为13。
1
2 3 4 5 6 7 8 9 10 11 |
#include int { } |
这个代码的结果又是多少呢?
这是一个错误代码,错误在于:
1
|
int |
首先对于编译器来说,它会从左向右的顺序一个一个尽可能多的读入字符,当即将读入的字符不可能和已读入的字符组成合法符号为止,所以它认为读完++i后会再读++,发现读完++后读不下去了才会停止,也就是说上述语句等价于:
1
|
int |
这也就等价于:
1
|
int |
上述语句3++明显是错误的表示,所以编译如上代码时会出错。
示例代码:
1
2 3 4 5 6 7 8 9 10 11 |
#include int { } |
结果为i = 4, j =6。因为i+++i+++i相当于先执行三次相加操作,即2+2+2,这是j的值。执行完语句后则会执行两次++操作,所以i由2变为4。
1
2 3 4 5 6 7 8 9 10 11 12 13 |
#include int { } |
大家知道short的优先级高于char,所以认为输出结果为2,实际上输出结果为4。
当char与short相加时会产生隐式转换,即产生为int类型。
参考
隐式转换表如下: