2021-03-12
五、字符串、转义字符和注释
1、字符串
定义:由双引号引起来的一串字符。除非特别定义,默认初始化会给结尾加上结束标志。注意:它的结束标志是 ‘\0’ 的转义字符,在计算字符串长度时不作内容。( 为了说清这一点,通过使用strlen ( ) 和sizeof ( ) 来对比 )
strlen ( ) 是用来求字符串有效长度的函数,长度的结束标志符是 ‘\0’ 。而sizeof是用来计算变量所占空间大小的操作符,与 ‘\0’ 无关。下面具体举例:
char arr1[] = "zuo"; //一般情况
char arr2[] = {'z','u','o'}; //对于strlen ( )结束不了
char arr3[] = {'z','u','o','\0'}; //对于sizeof ( ) ,'\0'也要计入
这段字符串的定义,如果使用strlen ( ) ,那它的结果分别为3,随机数,3;如果使用sizeof,那它的结果分别为4,3,4.
2、转义字符
转义字符属于字符型常量,所以在使用时需要用单引号引起来。转义
字符再加上一个 \ 就会变成普通字符。下面是常见的一些转义字符:
这里来做一个经典的题目:
int main()
{
printf("%d\n",strlen("c:\test1\678\name"));//这里输出是多少?
return 0;
}
这个题的答案是13,你做对了吗?思路:这个字符串里面有转义字符 ‘\t’ , ‘\67’ , ‘\n’ 。因为8不属于八进制,所以它单独算作一个长度。
3、注释
注释有两种,一种是/* */,还有一种是//。
前者有一个特点就是会寻找离它最近的第一个 */,把这一段注释掉,所以不可以嵌套使用。这也是它的一个缺点。
六、三大语句及函数,数组
一般语言的三大语句是顺序,选择(分支),循环。C语言也不例外。
函数的作用就是为了对代码进行简化和复用。一个函数只有一个返回值。函数可以嵌套调用,但是不可以嵌套定义!传值调用时改变形参不影响实参,传址调用会影响。函数不调用时形参没有内存空间,调用时才开辟空间。
数组的下标是从0开始的。
这部分由于内容较多,以后再做赘述,这里只是简单的列出框架。
七、操作符
1、算术操作符
+ - * / %
需要注意的是 ,对于除法运算,表达式都是整型,结果也是整型;只要出现浮点型,结果就是浮点型;对于取余运算,要求均为整型。
2、移位操作符
>> <<
分别是左移和右移。作移位运算时,移动的是其二进制位。(注意:移到的位数非负,不可以移动负数位)
左移:左边舍弃,右边补零。
右移:逻辑右移是左边补零,右边舍弃;算术右移是左边补符号位,右边舍弃。
3、位操作符
& ⋀ |
分别是与,异或,或。作位运算是按其二进制位进行运算。
- 例题:不创建中间变量,直接实现两个变量的值交换。
#include<stdio.h>
int main()
{
int a = 2;
int b = 3;
a = a ^ b;
b = a ^ b; //a ^ b = (a ^b) ^ b = a ^ (b ^ b) = a ^ 0 = a
a = a ^ b; //a ^ b = (a ^b) ^ a = (a ^ a) ^ b = 0 ^ b = b
printf("a = %d,b = %d\n", a, b);
return 0;
}
- 求一个整数存储在内存中的二进制位中的 1 的个数
#include<stdio.h>
int main()
{
int num1 = 8;
int num2 = -2;
int count = 0;
//方法一 不可以计算有符号负数
/*while (num1)
{
if ( (num1 % 2) == 1)
count++;
num1 /= 2;
}*/
//方法二 都可以计算,但是每次都要循环32遍,比较浪费资源
/*int i = 0;
for (i = 0; i < 32; i++)
{
if (((num2 >> i) & 1) == 1) //把数字右移与1相与,为1为真否则为假
{
count++;
}
}*/
//方法三 优化完毕
while (num2)
{
count++;
num2 &= (num2 - 1);
}
printf("1的个数是:%d\n", count);
return 0;
}
4、赋值操作符
= += -= *= /= &= ⋀= |= >>= <<=
5、单目操作符
只需要一个操作数的操作符叫单目操作符。
! 逻辑反操作
1. 负值
2. 正值
& 取地址
sizeof 计算变量或变量名所占空间大小,字节为单位
~ 对一个数的二进制位按位取反
++ 前置加一和后置加一
-- 前置减一和后置减一
3. 间接访问操作符也叫解引用操作符
(类型) 强制类型转换
这里主要摘出来说一下以下几个:
(1)整型a的值为0,那么~a的值是?-1
思路:计算机内部采用的是补码进行运算,a的二进制补码为32位0。
00000000 00000000 00000000 00000000 a的补码
11111111 11111111 11111111 11111111 ~a的补码
减一取反得到
10000000 00000000 00000000 00000001 即-1
(2)对于前置和后置运算(它是一个表达式),前置时先+1(或-1),再使用值;后置时先使用值再+1(或-1)
(3)对于强制类型转换操作符,用法如下:
int a = (int)1.5; //此时a的值为1
6、关系操作符
> >= < <= != ==
这里需要注意的是,一个 = 表示赋值,两个 = 才是判断关系。
7、逻辑操作符
&& || !
分别表示逻辑中的与,或,非。
- 例题:求输出结果?
#include<stdio.h>
int main()
{
int i = 0,a = 0,b = 2,c = 3,d = 4;
i = a++ && ++b && d++;
//i = a++ || ++b || d++;
printf("%d %d %d %d \n",a,b,c,d);
return 0;
}
- && 时,值为 1,2,3,4(只要判断为假,&&运算就不会再往后计算了,所以只给a作了自加1)
- || 时,值为1,3,3,4(只要判断为真,|| 运算就不会再往后计算了,所以当计算到 b 时,已经为真,就不会再给d 作自加1)
8、其它操作符
< exp1 >?< exp2 >:< exp3 > //条件操作符(三目)
, //逗号操作符
[ ] //下标引用操作符,用于数组
( ) //函数调用操作符,跟在函数名后面
. //直接访问结构体成员变量使用;结构体名.成员变量名
-> //通过结构体指针访问结构体成员变量使用;结构体指针名->结构体成员变量名
这里说以下几个:
- 条件操作符 : exp1为条件,条件为真执行exp2,条件为假执行exp3。
- 逗号操作符 : 用在逗号隔开的一串表达式,从左向右依次计算,结果是最后一个表达式结果。
八、表达式求值
求值顺序一部分由运算符的优先级和结合性决定。有些表达式的操作数在求值过程中有可能需要转化为其他类型。下面介绍两种隐式转换:
1、整型提升
CPU内整型运算器(ALU)的操作数的字节长度及通用寄存器的字节长度都是4个字节。因此,即使两个char型的数据相加,CPU实际执行时也要先转化为整型操作数标准长度。
通用CPU难以实现两个8bite直接相加运算,所以整型算术运算的表达式中的 char 和 short 类型的操作数在使用前要转换为 int 型,这种转换就叫整型提升。
- 整型提升的方法:有符号数,高位补充符号位;无符号数高位补0
- 实例:
- 注意:整型表达式进行计算时先做整型提升,再计算。例子如下:
int main()
{
char a = 0xa1;
short b = 0xa123;
int c = 0xa1234567;
if( a == 0xa1 )
{
printf("a\n");
}
if( b == 0xa123 )
{
printf("b\n");
}
if( c == 0xa1234567 )
{
printf("c\n");
}
return 0;
}
只输出 c 的原因:做条件判断整型表达式,a 和 b 进行了整型提升,变成了负数,结果为假;而 c 本来就是 int 型,不需要整型提升,结果为真。
2、算术转换
某个操作符的操作数属于不同数据类型,必须要把一个操作数转换为另一个操作数类型,否则操作无法进行。操作数的参差体系如下:
long double > double > float >unsigned long int > long int > unsigned int > int
九、关键字
c语言标准32个关键字如下:
这里主要摘出这几个说一下:
auto:自动变量就是自动创建,自动销毁的变量。局部变量即自动变量。
typedef:给类型重命名。
typedef unsigned int unit; //将unsigned int重命名为uint
static:用来修饰变量和函数的关键字。
1)修饰局部变量,改变局部变量的生命周期,使其与程序的生命周期一样。
#include <stdio.h>
int Add()
{
static int i = 0;
i++;
return i;
}
int main()
{
int i = 0;
for(i = 0;i < 5; i++)
test();
return 0;
}
本来对于变量 i 它的生命周期只有在Add函数内部,所以输出为五个1;在ADD函数内给 i 加上static关键字之后就它的生命周期变成了程序的生命周期,输出变成了1到5。
2)修饰全局变量,改变了全局变量的作用域,使得只能在自己的源文件中使用。
在其他源文件的内部是看不到或者说使用不了的。
3)修饰函数,改变了函数的使用范围,使得只能在自己的源文件中使用。
同样,在其他源文件的内部是看不到或者说使用不了的。