目录
1-7-4 位运算符(与、或、异或、取反、二进制左移和右移)
1-7 运算符
c语言中提供的运算符:
- 算术运算符
- 关系运算符
- 逻辑运算符
- 位运算符
- 赋值运算符
- 杂项运算符
1-7-1 算术运算符
假设变量 A 的值为 10,变量 B 的值为 20:
运算符 | 描述 | 实例 |
---|---|---|
+ | 把两个操作数相加 | A + B 将得到 30 |
- | 从第一个操作数中减去第二个操作数 | A - B 将得到 -10 |
* | 把两个操作数相乘 | A * B 将得到 200 |
/ | 分子除以分母 | B / A 将得到 2 |
% | 取模运算符,整除后的余数 | B % A 将得到 0 |
++ | 自增运算符,整数值增加 1 | A++ 将得到 A=11 |
-- | 自减运算符,整数值减少 1 | A-- 将得到 A=9 |
注意!A++是先赋值后运算,++A是先运算后赋值。
实例:
#include <stdio.h>
int main()
{
int a = 21;
int b = 10;
int c ;
c = a + b;
printf("Line 1 - c 的值是 %d\n", c );
c = a - b;
printf("Line 2 - c 的值是 %d\n", c );
c = a * b;
printf("Line 3 - c 的值是 %d\n", c );
c = a / b;
printf("Line 4 - c 的值是 %d\n", c );
c = a % b;
printf("Line 5 - c 的值是 %d\n", c );
c = a++; // 赋值后再加 1 ,c 为 21,a 为 22
printf("Line 6 - c 的值是 %d\n", c );
c = a--; // 赋值后再减 1 ,c 为 22 ,a 为 21
printf("Line 7 - c 的值是 %d\n", c );
c = ++b; // 先加 1 再赋值,b 为 11 ,c 为 11
printf("Line 8 - c 的值是 %d\n", c );
c = --b; // 先减 1 再赋值,b 为 10 ,a 为 10
printf("Line 9 - c 的值是 %d\n", c );
}
以上代码编译结果为:
Line 1 - c 的值是 31
Line 2 - c 的值是 11
Line 3 - c 的值是 210
Line 4 - c 的值是 2
Line 5 - c 的值是 1
Line 6 - c 的值是 21
Line 7 - c 的值是 22
Line 8 - c 的值是 11
Line 9 - c 的值是 10
1-7-2 关系运算符
假设变量 A 的值为 10,变量 B 的值为 20:
运算符 | 描述 | 实例 |
---|---|---|
== | 检查两个操作数的值是否相等,如果相等则条件为真。 | (A == B) 不为真。 |
!= | 检查两个操作数的值是否相等,如果不相等则条件为真。 | (A != B) 为真。 |
> | 检查左操作数的值是否大于右操作数的值,如果是则条件为真。 | (A > B) 不为真。 |
< | 检查左操作数的值是否小于右操作数的值,如果是则条件为真。 | (A < B) 为真。 |
>= | 检查左操作数的值是否大于或等于右操作数的值,如果是则条件为真。 | (A >= B) 不为真。 |
<= | 检查左操作数的值是否小于或等于右操作数的值,如果是则条件为真。 | (A <= B) 为真。 |
实例:
#include <stdio.h>
int main()
{
int a = 21;
int b = 10;
int c ;
if( a == b )
{
printf("Line 1 - a 等于 b\n" );
}
else
{
printf("Line 1 - a 不等于 b\n" );
}
if ( a < b )
{
printf("Line 2 - a 小于 b\n" );
}
else
{
printf("Line 2 - a 不小于 b\n" );
}
if ( a > b )
{
printf("Line 3 - a 大于 b\n" );
}
else
{
printf("Line 3 - a 不大于 b\n" );
}
/* 改变 a 和 b 的值 */
a = 5;
b = 20;
if ( a <= b )
{
printf("Line 4 - a 小于或等于 b\n" );
}
if ( b >= a )
{
printf("Line 5 - b 大于或等于 a\n" );
}
}
将以上代码编译得到结果:
Line 1 - a 不等于 b
Line 2 - a 不小于 b
Line 3 - a 大于 b
Line 4 - a 小于或等于 b
Line 5 - b 大于或等于 a
1-7-3 逻辑运算符(逻辑与或非)
假设变量 A 的值为 1(或29),变量 B 的值为 0:
运算符 | 描述 | 实例 |
---|---|---|
&& | 称为逻辑与运算符。如果两个操作数都非零,则条件为真。 | (A && B) 为假。 |
|| | 称为逻辑或运算符。如果两个操作数中有任意一个非零,则条件为真。 | (A || B) 为真。 |
! | 称为逻辑非运算符。用来逆转操作数的逻辑状态。如果条件为真则逻辑非运算符将使其为假。 |
实例:
#include <stdio.h>
int main()
{
int a = 5;
int b = 20;
int c ;
if ( a && b )
{
printf("Line 1 - 条件为真\n" );
}
if ( a || b )
{
printf("Line 2 - 条件为真\n" );
}
/* 改变 a 和 b 的值 */
a = 0;
b = 10;
if ( a && b )
{
printf("Line 3 - 条件为真\n" );
}
else
{
printf("Line 3 - 条件不为真\n" );
}
if ( !(a && b) )
{
printf("Line 4 - 条件为真\n" );
}
}
将以上代码编译得到结果:
Line 1 - 条件为真
Line 2 - 条件为真
Line 3 - 条件不为真
Line 4 - 条件为真
1-7-4 位运算符(与、或、异或、取反、二进制左移和右移)
位运算符作用于位,并逐位执行操作。
&、 | 和 ^ 的真值表如下所示:
p | q | p & q(与) | p | q(或) | p ^ q(异或) |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 0 |
1 | 0 | 0 | 1 | 1 |
假设如果 A = 60,且 B = 13,现在以二进制格式表示,它们如下所示:
A = 0011 1100
B = 0000 1101
-----------------
A&B = 0000 1100
A|B = 0011 1101
A^B = 0011 0001
~A = 1100 0011
下表显示了 C 语言支持的位运算符。
假设变量 A 的值为 60,变量 B 的值为 13,则:
运算符 | 描述 | 实例 |
---|---|---|
& | 按位与操作,按二进制位进行"与"运算。运算规则:0&0=0; 0&1=0; 1&0=0; 1&1=1; | (A & B) 将得到 12,即为 0000 1100 |
| | 按位或运算符,按二进制位进行"或"运算。运算规则:`0 | 0=0; 0 |
^ | 异或运算符,按二进制位进行"异或"运算。运算规则:0^0=0; 0^1=1; 1^0=1; 1^1=0; | (A ^ B) 将得到 49,即为 0011 0001 |
~ | 取反运算符,按二进制位进行"取反"运算。运算规则:~1=0; ~0=1; | (~A ) 将得到 -61,即为 1100 0011,一个有符号二进制数的补码形式。 |
<< | 二进制左移运算符。将一个运算对象的各二进制位全部左移若干位(左边的二进制位丢弃,右边补0)。 | A << 2 将得到 240,即为 1111 0000 |
>> | 二进制右移运算符。将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃。 | A >> 2 将得到 15,即为 0000 1111 |
注意!取反(~)就说先按位取反,然后求补码(正数负数求补码不一样)!
- 正数的补码=原码
- 负数的补码={原码符号不变}+{数值位按位取反后+1}
/*
二进制中第一位是符号位。(正数位0,负数为1)
1 1 1 1 1111
负 64 32 16 8421
*/
a=60,60的二进制:0011 1100(最前面的0表示正数)
~a,a取反:
首先按位取反变成1100 0011(最前面的1表示负数);
负数取补码:最前面1(不变),后面的100 0011再取反,后加一
也就是1011 1100 +1 =1011 1101,即-61。
实例:
#include <stdio.h>
int main()
{
unsigned int a = 60; /* 60 = 0011 1100 */
unsigned int b = 13; /* 13 = 0000 1101 */
int c = 0;
c = a & b; /* 12 = 0000 1100 */
printf("Line 1 - c 的值是 %d\n", c );
c = a | b; /* 61 = 0011 1101 */
printf("Line 2 - c 的值是 %d\n", c );
c = a ^ b; /* 49 = 0011 0001 */
printf("Line 3 - c 的值是 %d\n", c );
c = ~a; /*-61 = 1011 1101 */
//0011 1100 取反-->1100 0011 负数取补码-->1011 1101,即-61
printf("Line 4 - c 的值是 %d\n", c );
c = a << 2; /* 240 = 00 1111 0000 */ //符号位不会变,还是正数
//左移:整体左移,后面补零。a左移5位为0111 1000 0000
printf("Line 5 - c 的值是 %d\n", c );
c = a >> 2; /* 15 = 0000 1111 */
//右移:从右边开始抹掉数,前面补零。a右移4位为0000 0011
printf("Line 6 - c 的值是 %d\n", c );
}
上面的代码被编译后结果:
Line 1 - c 的值是 12
Line 2 - c 的值是 61
Line 3 - c 的值是 49
Line 4 - c 的值是 -61
Line 5 - c 的值是 240
Line 6 - c 的值是 15
1-7-5 赋值运算符
运算符 | 描述 | 实例 |
---|---|---|
= | 简单的赋值运算符,把右边操作数的值赋给左边操作数 | C = A + B 将把 A + B 的值赋给 C |
+= | 加且赋值运算符,把右边操作数加上左边操作数的结果赋值给左边操作数 | C += A 相当于 C = C + A |
-= | 减且赋值运算符,把左边操作数减去右边操作数的结果赋值给左边操作数 | C -= A 相当于 C = C - A |
*= | 乘且赋值运算符,把右边操作数乘以左边操作数的结果赋值给左边操作数 | C *= A 相当于 C = C * A |
/= | 除且赋值运算符,把左边操作数除以右边操作数的结果赋值给左边操作数 | C /= A 相当于 C = C / A |
%= | 求模且赋值运算符,求两个操作数的模赋值给左边操作数 | C %= A 相当于 C = C % A |
<<= | 左移且赋值运算符 | C <<= 2 等同于 C = C << 2 |
>>= | 右移且赋值运算符 | C >>= 2 等同于 C = C >> 2 |
&= | 按位与且赋值运算符 | C &= 2 等同于 C = C & 2 |
^= | 按位异或且赋值运算符 | C ^= 2 等同于 C = C ^ 2 |
|= | 按位或且赋值运算符 | C |= 2 等同于 C = C | 2 |
实例:
#include <stdio.h>
main()
{
int a = 21;
int c ;
c = a;
printf("=运算符实例,c 的值 = %d\n", c );
c += a;
printf("+=运算符实例,c 的值 = %d\n", c );
c -= a;
printf("-=运算符实例,c 的值 = %d\n", c );
c *= a;
printf("*=运算符实例,c 的值 = %d\n", c );
c /= a;
printf("/=运算符实例,c 的值 = %d\n", c );
c = 200;
c %= a;
printf("%=运算符实例,c 的值 = %d\n", c );
c <<= 2;
printf("<<=运算符实例,c 的值 = %d\n", c );
c >>= 2;
printf(">>=运算符实例,c 的值 = %d\n", c );
c &= 2;
printf("&=运算符实例,c 的值 = %d\n", c );
c ^= 2;
printf("^=运算符实例,c 的值 = %d\n", c );
c |= 2;
printf("|=运算符实例,c 的值 = %d\n", c );
}
以上代码运算结果为:
=运算符实例,c 的值 = 21
+=运算符实例,c 的值 = 42
-=运算符实例,c 的值 = 21
*=运算符实例,c 的值 = 441
/=运算符实例,c 的值 = 21
=运算符实例,c 的值 = 11
<<=运算符实例,c 的值 = 44
>>=运算符实例,c 的值 = 11
&=运算符实例,c 的值 = 2
^=运算符实例,c 的值 = 0
|=运算符实例,c 的值 = 2
1-7-6 杂项运算符
下表列出了 C 语言支持的其他一些重要的运算符:
运算符 | 描述 | 实例 |
---|---|---|
sizeof() | 返回变量的大小。 | sizeof(a) 将返回 4,其中 a 是整数。 |
& | 返回变量的地址。 | &a; 将给出变量的实际地址。 |
* | 指向一个变量。 | *a; 将指向一个变量。 |
? :(三元) | 条件表达式 | 如果条件为真 ? 则值为 X : 否则值为 Y |
实例:
#include <stdio.h>
int main()
{
int a = 4;
short b;
double c;
int* ptr;
/* sizeof 运算符实例 */
printf("Line 1 - 变量 a 的大小 = %lu\n", sizeof(a) ); //a是int型,sizeof(a)为4个字节
printf("Line 2 - 变量 b 的大小 = %lu\n", sizeof(b) ); //b是short型,sizeof(b)为2个字节
printf("Line 3 - 变量 c 的大小 = %lu\n", sizeof(c) ); //a是double型,sizeof(c)为8个字节
/* & 和 * 运算符实例 */
ptr = &a; /* 'ptr' 现在包含 'a' 的地址 */
printf("a 的值是 %d\n", a);
printf("*ptr 是 %d\n", *ptr);
/* 三元运算符实例 */
a = 10;
b = (a == 1) ? 20: 30; //a==1是否为真,若真b等于20,若假b等于30
printf( "b 的值是 %d\n", b );
b = (a == 10) ? 20: 30;
printf( "b 的值是 %d\n", b );
}
以上代码运行后结果为:
Line 1 - 变量 a 的大小 = 4
Line 2 - 变量 b 的大小 = 2
Line 3 - 变量 c 的大小 = 8
a 的值是 4
*ptr 是 4
b 的值是 30
b 的值是 20
1-7-7 运算符优先级
类别 | 运算符 | 结合性 |
---|---|---|
后缀 | () [] -> . ++ - - | 从左到右 |
一元 | + - ! ~ ++ - - (type)* & sizeof | 从右到左 |
乘除 | * / % | 从左到右 |
加减 | + - | 从左到右 |
移位 | << >> | 从左到右 |
关系 | < <= > >= | 从左到右 |
相等 | == != | 从左到右 |
位与 AND | & | 从左到右 |
位异或 XOR | ^ | 从左到右 |
位或 OR | | | 从左到右 |
逻辑与 AND | && | 从左到右 |
逻辑或 OR | || | 从左到右 |
条件 | ?: | 从右到左 |
赋值 | = += -= *= /= %=>>= <<= &= ^= |= | 从右到左 |
逗号 | , | 从左到右 |
实例:
#include <stdio.h>
main()
{
int a = 20;
int b = 10;
int c = 15;
int d = 5;
int e;
e = (a + b) * c / d; // ( 30 * 15 ) / 5
printf("(a + b) * c / d 的值是 %d\n", e );
e = ((a + b) * c) / d; // (30 * 15 ) / 5
printf("((a + b) * c) / d 的值是 %d\n" , e );
e = (a + b) * (c / d); // (30) * (15/5)
printf("(a + b) * (c / d) 的值是 %d\n", e );
e = a + (b * c) / d; // 20 + (150/5)
printf("a + (b * c) / d 的值是 %d\n" , e );
return 0;
}
运行以上代码的结果为:
(a + b) * c / d 的值是 90
((a + b) * c) / d 的值是 90
(a + b) * (c / d) 的值是 90
a + (b * c) / d 的值是 50
1-8 判断
C 语言把任何非零和非空的值假定为 true,把零或 null 假定为 false。
判断语句
语句 | 描述 |
---|---|
if 语句 | 一个 if 语句 由一个布尔表达式后跟一个或多个语句组成。 |
if...else 语句 | 一个 if 语句 后可跟一个可选的 else 语句,else 语句在布尔表达式为假时执行。 |
嵌套 if 语句 | 您可以在一个 if 或 else if 语句内使用另一个 if 或 else if 语句。 |
switch 语句 | 一个 switch 语句允许测试一个变量等于多个值时的情况。 |
嵌套 switch 语句 | 您可以在一个 switch 语句内使用另一个 switch 语句。 |
?:运算符(三元运算符)
前面提到的条件运算符?:可以用来代替if...else语句。它的形式如下:
b = Exp1 ? Exp2 : Exp3;
判断Exp1是否为真,若真b等于Exp2的值,若假b等于Exp3的值。
实例:
#include<stdio.h>
int main()
{
int num;
printf("输入一个数字 : ");
scanf("%d",&num); //scanf()函数:输入
(num%2==0)?printf("偶数"):printf("奇数"); //判断num的奇偶
}
若运行后,输入8,回车则显示“偶数”;若输入5,则显示“奇数”。
1-9 循环
循环语句允许我们多次执行一个语句或语句组。
1-9-1 循环类型
循环类型 | 描述 |
---|---|
while 循环 | 当给定条件为真时,重复语句或语句组。它会在执行循环主体之前测试条件。(测试条件执行) |
for 循环 | 多次执行一个语句序列,简化管理循环变量的代码。 |
do...while 循环 | 除了它是在循环主体结尾测试条件外,其他与 while 语句类似。(先执行一次,再测试条件执行) |
嵌套循环 | 您可以在 while、for 或 do..while 循环内使用一个或多个循环。 |
1-9-2 循环控制语句
控制语句 | 描述 |
---|---|
break 语句 | 终止循环或 switch 语句,程序流将继续执行紧接着循环或 switch 的下一条语句。 |
continue 语句 | 告诉一个循环体立刻停止本次循环迭代,重新开始下次循环迭代。 |
goto 语句 | 将控制转移到被标记的语句。但是不建议在程序中使用 goto 语句。 |
1-9-3 无限循环
如果条件永远不为假,则循环将变成无限循环。for 循环在传统意义上可用于实现无限循环。由于构成循环的三个表达式中任何一个都不是必需的,您可以将某些条件表达式留空来构成一个无限循环。
例:
#include <stdio.h>
int main ()
{
for( ; ; )
{
printf("该循环会永远执行下去!\n");
}
return 0;
}
当条件表达式不存在时,它被假设为真。可以设置一个初始值和增量表达式,可使用 for(;;) 结构来表示一个无限循环。
注意:您可以按 Ctrl + C 键终止一个无限循环。
1-10 函数
每个 C 程序都至少有一个函数,即主函数 main() ,所有简单的程序都可以定义其他额外的函数。
函数声明告诉编译器函数的名称、返回类型和参数。函数定义提供了函数的实际主体。
C 标准库提供了大量的程序可以调用的内置函数。
1-10-1 定义函数
C语言中的函数定义的一般形式如下:
return_type function_name( parameter list )
{
body of the function
}
- 返回类型(return_type):一个函数可以返回一个值。return_type是函数返回的值的数据类型。有些函数执行所需的操作而不返回值,在这种情况下,return_type 是关键字 void。
- 函数名称(function_name):这是函数的实际名称。函数名和参数列表一起构成了函数签名。
- 参数(parameter list):参数就像是占位符。当函数被调用时,向参数传递一个值,这个值被称为实际参数,代入值的参数在被调用的函数中运用。参数列表包括函数参数的类型、顺序、数量。参数是可选的,也就是说,函数可能不包含参数。
- 函数主体(body of the function):函数主体包含一组定义函数执行任务的语句。
实例:
/* 函数返回两个数中较大的那个数 */
int max(int num1, int num2)
{
/* 局部变量声明 */
int result;
if (num1 > num2)
result = num1;
else
result = num2;
return result;
}
1-10-2 函数声明
函数声明会告诉编译器函数名称及如何调用函数。函数的实际主体可以单独定义。
函数声明包括以下几个部分:
return_type function_name( parameter list );
对于1-10-1定义的函数max()例子,以下是它的函数声明:
int max(int num1, int num2);
在函数声明中,参数的名称并不重要,只有参数的类型是必需的,因此下面也是它的有效的声明:
int max(int, int);
当在一个源文件中定义函数且在另一个文件中调用函数时,函数声明是必需的。在这种情况下,应该在调用函数的文件顶部声明函数。
1-10-3 调用函数
当程序调用函数时,程序控制权会转移给被调用的函数。被调用的函数执行已定义的任务,当函数的返回语句被执行时,或到达函数的结束括号时,会把程序控制权交还给主程序。
调用函数时,传递所需参数,如果函数返回一个值,则可以存储返回值。
实例:
#include <stdio.h>
/* 函数声明 */
int max(int num1, int num2);
int main ()
{
/* 局部变量定义 */
int a = 100;
int b = 200;
int ret;
/* 调用函数来获取最大值 */
ret = max(a, b);
printf( "Max value is : %d\n", ret );
return 0;
}
/* 函数返回两个数中较大的那个数 */
int max(int num1, int num2)
{
/* 局部变量声明 */
int result;
if (num1 > num2)
result = num1;
else
result = num2;
return result;
}
把 max() 函数和 main() 函数放一块,编译源代码。运行后结果:
Max value is : 200
1-10-4 函数参数
如果函数要使用参数,则必须声明接受参数值的变量。这些变量称为函数的形式参数。
形式参数就像函数内的其他局部变量,在进入函数时被创建,退出函数时被销毁。
当调用函数时,有三种向函数传递参数的方式:
参数调用类型 | 描述 |
---|---|
传值调用 | 该方法把参数的实际值复制给函数的形式参数。在这种情况下,修改函数内的形式参数不会影响实际参数。(例:b=a;b++;//修改了b的值,a的值也不会变。这是传值调用) |
指针调用 | 通过指针传递方式,形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作。(例:int *x = &a ; //把a的地址传给x) |
引用调用/引址调用 | 引用调用是函数传递参数的一种方式,主函数可以在子函数中对形参所做的更改对主函数中的实参有效。与指针调用类似。 |
以下俩实例参考出处:C++ 引用调用、指针调用、传值调用(非常方便理解)_c++函数的引用调用和传值调用-CSDN博客
引用调用的实例:
#include <iostream>
using namespace std;
// 函数声明
void swap(int &诸葛孔明);
/*
在swap()中,诸葛孔明就是诸葛亮。
在swap函数里,实际参数叫诸葛孔明。
在主函数里,调用swap时形式参数的名字叫诸葛亮。
虽然名字叫法不同,但是人还是同一个人,参数还是一样的参数。
*/
// 主函数定义
int main ()
{
// 局部变量声明
int 诸葛亮 = 100;
cout << "交换前,诸葛亮的值:" << 诸葛亮 << endl;
/*
注:c++中,cout是意思是输出,endl的意思是换行,他俩不能一起写,每个前面要加"<<"。
cout<<endl<<"内容";
例:cout<<"咏鹅";cout<<endl<<"鹅鹅鹅,"<<"曲项向天歌。"<<endl<<"白毛浮绿水,";
*/
/* 调用函数来交换值 */
swap(诸葛亮);
cout << "交换后,诸葛亮的值:" << 诸葛亮 << endl;
return 0;
}
// swap函数定义
void swap(int &诸葛孔明)//意思是int &诸葛孔明 = 诸葛亮,建立一个int型的引用诸葛孔明,并将其初始化为变量诸葛亮的一个别名诸葛孔明
{
int temp = 200;
诸葛孔明 = temp; /* 把 temp的值赋值给诸葛孔明 */
/* 诸葛孔明是诸葛亮的引用,或者说是别名,所以改变诸葛孔明的值,就是改变诸葛亮的值 */
return;
}
结果:
交换前,诸葛亮 的值:100
交换后,诸葛亮 的值:200
指针调用的实例:
int *x=&a //把a的地址传给x
#include <iostream>
using namespace std;
// 函数声明
void swap(int *x, int *y);
int main ()
{
// 局部变量声明
int a = 100;
int b = 200;
cout << "交换前,a 的值:" << a << endl;
cout << "交换前,b 的值:" << b << endl;
/* 调用函数来交换值
* &a 表示指向 a 的指针,即变量 a 的地址
* &b 表示指向 b 的指针,即变量 b 的地址
*/
swap(&a, &b);
cout << "交换后,a 的值:" << a << endl;
cout << "交换后,b 的值:" << b << endl;
return 0;
}
// 函数定义
void swap(int *x, int *y)
{
int temp;
temp = *x; /* 保存地址 x 的值 */
*x = *y; /* 把 y 赋值给 x */
*y = temp; /* 把 x 赋值给 y */
return;
}
结果:
交换前,a 的值: 100
交换前,b 的值: 200
交换后,a 的值: 200
交换后,b 的值: 100