コンテンツ
2.1:シフト演算子(オペランドは整数のみにすることができます)
3.1:ビット演算子(オペランドは整数である必要があります)
3.4演習:2つの数値を交換するための一時変数(3番目の変数)を作成することはできません。
4.1。演習の例:達成するコードを書く:メモリに格納されている整数のバイナリで1の数を見つけます。
概要:作成する式で演算子のプロパティを介して一意の計算パスを決定できない場合、式に問題があります。
1.1:算術演算子
+-* /%
int main()
{
float a = 3 / 2;
printf("%f", a);//答案是1,错误写法
return 0;
}
int main()
{
float a = 3 / 2.0;//在整数后面加小数点即可,答案1.5
printf("%f", a);
return 0;
}
int main()
{
float a = 3 % 2;
printf("%d", a);//3/2...1,结果是1,得到的是余数
return 0;
}
1:結果1.5を取得したいのですが、除算記号の両側に整数があるため、結果は1.000000になります。実行できるのは、整数除算のみです。3/2剰余1
2:任意の整数に浮動小数点数を追加し、10進数の除算を実行します
3:モジュロオペランドの場合、式の左と右の値は整数である必要があります
2.1:シフト演算子(オペランドは整数のみにすることができます)
<<左シフト演算子(シフト規則:左側を2進数で破棄し、右側に0を追加します)
>>右シフト演算子(シフト規則:1。算術右シフト:右側を2進数で破棄し、左側の符号ビットを補完します)
2.論理右シフト:右側を破棄し、左側をゼロで埋めます
整数のバイナリ表現には、元のコード、逆コード、および補数コードの3つの形式があります。
正の整数の元のコード、逆コード、および補数コードは同じ
です。負の整数の元のコード、逆コード、および補数コードを計算する必要があります。
整数は2の補数の2進数としてメモリに格納されます
2進数では、数値が符号付きの場合、最上位ビットは符号ビットです(正の数の場合は0、負の数の場合は1)
2.2質問の例:
int main()
{
int a = -1;
-1的二进制位 原码10000000000000000000000000000001;(第一位1表示负数)
反码11111111111111111111111111111110 (原码符号位不变,其他位按位取反)
补码11111111111111111111111111111111 (反码加1得到补码)
负数的原反是补是算出来的
return 0;
}
2.3質問の例:
int main()
{
int a = 2;
printf("%d",a << 1);
return 0;
}
a写成二进制是00000000000000000000000000000010
<<移动1位,遵循左边丢弃,右边补0,变成00000000000000000000000000000100,答案是4
2.4質問の例:
int main()
{
int a = -2;
printf("%d",a << 1);(实际上打印的是原码)
return 0;
}
原码:10000000000000000000000000000010
反码:11111111111111111111111111111101
补码:11111111111111111111111111111110 (a在内存中存的二进制序列)
<<1一位,11111111111111111111111111111110变成11111111111111111111111111111100
11111111111111111111111111111100(补码)
11111111111111111111111111111011(-1得到反码)
10000000000000000000000000000100 (答案是4)
注:aの値は変更されません
2.5:>>右シフト演算子
int main()
{
int a = 5; //00000000000000000000000000000101
int b = a >> 1;//00000000000000000000000000000010
printf("%d %d",a,b);
return 0;
}
int main()
{
int a = -5;
原码:10000000000000000000000000000101
反码:11111111111111111111111111111010
补码:11111111111111111111111111111011
int b = a >> 1;
补码(采用算术右移,补原符号位):11111111111111111111111111111101
反码(-1):11111111111111111111111111111100
原码:10000000000000000000000000000011
答案:b=-3
printf("%d %d",a,b);
return 0;
}
現在のコンパイラでは、右シフトが算術右シフトを実行するか、算術右シフトを実行するか、論理右シフトを実行するかは、コンパイラによって異なります。
シフト演算子は負のビットをシフトしません。これは標準で定義されていません。
3.1:ビット演算子(オペランドは整数である必要があります)
&ビット単位AND(バイナリ)ビット単位ビット:両方とも1、結果は1、それ以外の場合は0
|ビット単位のOR(バイナリ)対応するバイナリビット:1は1であり、同時に0は0です。
^ビット単位のXOR(バイナリ)//対応するバイナリビット:同じビットは0、差は1
3.2:練習
int main()
{
int a = 3;
int b = -5;
//00000000000000000000000000000011 -> 3的补码
//11111111111111111111111111111011 -> -5的补码
int c = a & b;
//00000000000000000000000000000011
答案是3
int c = a | b;
//11111111111111111111111111111011
答案是-5
int c = a ^ b;
//11111111111111111111111111111000
//11111111111111111111111111110111
//10000000000000000000000000001000
答案是-8
printf("%d\n", c);
return 0;
}
3.3。演習:配列では、1つの数字だけが一度表示され、残りの数字はペアで表示されます。一度だけ表示される配列を見つけます(自分で書き留めます)。
ヒント:1。数値はそれ自体とXORされ、対応する2進ビットは同じであり、結果は0です。
2.0および任意の数のXORはそれ自体です
3.4演習:2つの数値を交換するための一時変数(3番目の変数)を作成することはできません。
int main()
{
int a = 3;
int b = 5;
printf("a=%d b=%d\n", a, b);
a = a + b;
b = a - b;
a = a - b; //写法1,数字太大会出错
a = a ^ b;
b = a ^ b;
a = a ^ b; //写法二
a=011(二进制位) b=101
a=a^b (a=110)
b=a^b (b=011) 此时,a的内容是110,b的内容变成011
a=a^b (a=101) 你会发现,异或后a和b二进制颠倒了
也可以这么理解,把a=a^b代入b=a^b中, 变成b=b^b^a,由于b^b=0, 0^a=a,相当于把a放到b中
printf("a=%d b=%d\n", a, b);
return 0;
}
3.5:2つの数値の2進数の異なるビット数を見つけます
int NumberOf1(int n)
{
int count = 0;
while (n)
{
n = n & (n - 1);
count++;
}
return count;
}
int main()
{
int m = 0;
int n = 0;
scanf("%d%d", &m, &n);
int count = 0;
int ret = m ^ n;
count = NumberOf1(ret);
printf("%d", count);
return 0;
}
4.1。演習の例:達成するコードを書く:メモリに格納されている整数のバイナリで1の数を見つけます。
int main()
{
int a = 5;
scanf("%d",&a);
int count = 0;
for (int i = 0; i < 32; i++)
{
if (((a >> i) & 1) == 1) //a&1,得到最低位是否为1
count++;
}
printf("%d", count);
return 0;
}
5.1:代入演算子
int main()
{
int weight =120;
weight =100;//赋值修改
int a = 10;
int x = 0;
int y = 20;
a=x=y+1;//连续赋值
//先执行x=y+1,最后x=21,a=21 不推荐这种写法
return 0;
}
5.2:複合代入(+ =-= * = / =%= >> = << =&= | = ^ =)
int main()
{
int a = 10;
a = a + 2;
a += 2;//等价
a = a >> 1;
a >>= 1;//等价
a = a & 4;
a &= 4;//等价
return 0;
}
6.1:単項演算子
!論理的逆演算子
+-正と負の値
&アドレスを取得
sizeofオペランドタイプの長さ(バイト単位)
〜数値のビットをビットごとに反転します
++には前と後があります
-フロントとリア付き
*間接参照演算子
(型)キャスト
6.2:質問の例
struct S
{
char name[20];
int age;
};
int main()
{
//& 取地址操作符
//* 解引用操作符(间接访问操作符)
int a = 10;
int* pa = &a;//把a的地址放在int*指针中
*pa = 20;//* - 解引用操作符
int arr[10] = {0};
&arr;//取出数组的地址,数组的地址应该放到【数组指针】中去
struct S s = {0};
struct S* ps = &s;
return 0;
}
6.3:sizeofの例
sizeof是一个操作符,不是函数
计算类型创建的变量所占内存的大小,单位是字节
int main()
{
int a = 10;
printf("%d\n", sizeof a);//可以省略阔号
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(int));//当它是类型不可以省略
int arr[10] = { 0 };
printf("%d\n", sizeof(arr)); //40个字节
int a = 10;
short s = 0;
printf("%d\n", sizeof(s = a + 2));//打印出来是2,a还是10,sizeof()中的表达式不参与计算
printf("%d\n", s);//s的值是0,s=a+2,a是整形,把整形放到短整型中还是短整型
return 0;
}
sizeofは、コンパイル中に取得される式の結果を評価しています
void test1(int arr[])
{
printf("%d\n", sizeof(arr));// 4/8传过来的是int*指针,指针占内存空间4/8字节
}
void test2(char arr[])
{
printf("%d\n", sizeof(arr));// 4/8传过来的是char*指针,指针占内存空间4/8字节
}
int main()
{
int arr1[10] = { 0 };
printf("%d\n", sizeof(arr));//40
char arr2[10] = { 0 };
printf("%d\n", sizeof(arr));//10
test1(arr1);
test2(arr2);
return 0;
}
6.3:単項演算子の演習
int main()
{
int a = 3;
int b = ++a;//前置++,先++,后使用//a=a+1,b=a
int b = a++;//后置++,先使用,后++。//b=a,a=a+1
int b = --a;//前置--,先--,后使用 //a=a-1,b=a
int b = a--;//后置--,先使用,再-- //b=a,a=a-1
return 0;
}
int main()
{
int a = (int)3.14;//类型不匹配,把3.14浮点型数字强制类型转换成int类型数据
printf("%d\n", a);
return 0;
}
7.1:関係演算子
>>
> =
<
<=
!=(同等性のテスト)
==(テストの同等性)==を使用して文字列を比較することはできず、strcmpを使用する必要があります
注:それが=(割り当て)であるか==(同等の判断)であるかを常に注意する必要があります
8.1:論理演算子
&&論理積
||論理または
int main()
{
int a = 1;
int b = 0;
if (a && b)
{
printf("hehe\n");//跟数学中的且,或一样,两个同时满足为真
}
if (a || b)
{
printf("hehe\n");一个满足为真
}
return 0;
}
8.2:&&および||演習
#include <stdio.h>
int main()
{
int i = 0, a = 0, b = 2, c = 3, d = 4;
i = a++ && ++b && d++;
printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
//答案是1,2,3,4
左边&& a++后置,先计算后++,为假,后面不计算,只计算了a++
int i = 0, a = 1, b = 2, c = 3, d = 4;
i = a++ || ++b || d++;
printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
//答案是2,2,3,4,a为真后面不计算
return 0;
}
9.1:条件演算子(3項演算子)
exp1?exp2:exp3
int main()
{
if (a > 5)
b = 3;
else
b = -3;
写成:
b = (a > 5 ? 3 : -3);//a>5 ? 是为判断1,否为判断2
找出两个数中最大的数字
int a = 3;
int b = 0;
int m = (a > b ? a : b);
return 0;
}
10.1:コンマ式
左から右に実行されるコンマ式。式全体の結果は、最後の式の結果です。
int main()
{
int a = 1;
int b = 2;
int c = (a > b, a = b + 10, a, b = a + 1);
printf("a=%d b=%d\n", a, b);
printf("%d\n", c);
return 0;
}
答案是a=12,b=13,c=13
a>b不产生影响,表达式为假 ->a=12 -> b=13 把13赋值给c
11.1:添え字参照、関数呼び出し、および構造体メンバー
[ ]下标引用操作符
int main()
{
int arr[10] = { 0 };
printf("%d\n", arr[1]);
printf("%d\n", 4[arr]);
printf("%d\n", *(arr + 1));//等价写法
return 0;
}
() 函数调用操作符
int main()
{
int ret = Add(2, 3);//()函数调用操作符,操作数就是:Add,2,3
printf("%d\n", ret);
return 0;
}
struct Stu
{
char name[20];
int age;
float score;
};
//结构体变量.成员名
void print1(struct Stu ss)
{
printf("%s %d %f\n", ss.name, ss.age, ss.score);
}
//结构体指针->成员名(指针接收)
void print2(struct Stu* ps)
{
//printf("%s %d %f\n", (*ps).name, (*ps).age, (*ps).score);
printf("%s %d %f\n", ps->name, ps->age, ps->score);
int main()
{
struct Stu s = {"张三", 20, 90.5f};
print1(s);
print2(&s);
return 0;
}
12.1:暗黙の型変換
式の評価順序は、演算子の優先順位と結合性によって部分的に決定されます
また、一部の式のオペランドは、評価時に他の型に変換する必要がある場合があります
Cでの計算は、少なくとも整数で行われます。
汎用CPUが2つの8ビットバイトを直接加算することは困難です(ただし、マシン命令にそのようなバイト加算命令がある場合があります)。したがって、長さが式のintの長さよりも短い可能性があるさまざまな整数値は、操作を実行するためにCPUに送信する前に、intまたはunsignedintに変換する必要があります。
int main()
{
char c1 = 3;
//00000011 - c1
//00000000000000000000000000000011
char c2 = 127;
//01111111 - c2
//00000000000000000000000001111111
char c3 = c1 + c2;
c1+c2是char类型,需要整型提升(按照符号位提升)
//00000000000000000000000000000011
//00000000000000000000000001111111
//00000000000000000000000010000010
//10000010 - c3 char类型截断,只能存八个比特位,最高位为负数
//11111111111111111111111110000010
//11111111111111111111111110000001
//10000000000000000000000001111110
//-126
printf("%d\n", c3);
return 0;
}
12.2:整数拡張の例
int main()
{
char a = 0xb6;//10110110
short b = 0xb600;
int c = 0xb6000000;
if (a == 0xb6)
printf("a");
if (b == 0xb600)
printf("b");
if (c == 0xb6000000)
printf("c");
return 0;
}
打印c
a发生整型提升,高位负数,b同理
int main()
{
char c = 1;
printf("%u\n", sizeof(c));//1
printf("%u\n", sizeof(+c));//4
printf("%u\n", sizeof(-c));//4
return 0;
}
c参与了表达式运算,发生了整型提升
12.3:算術変換
演算子のオペランドの型が異なる場合、一方のオペランドをもう一方のオペランドの型に変換しないと、演算を実行できません。算術変換は、型ランクに従って変換されます。
タイプがint未満の場合、charとshortは整数でプロモートされ、int以上のタイプで算術変換が実行されます。
long double
double
float
unsigned long int
long int
unsigned int
int
unsigned int 和int 类型一起,int转换为unsigned int类型
float f = 3.14;
int num = f;//隐式类型转换,float精度丢失
12.4:演算子の属性
複雑な式の評価に影響を与える3つの要因があります。
1.演算子の優先順位
⒉演算子の結合性
3.評価順序を管理するかどうか。(&& ||三項演算子)
int main()
{
int a = 10;
int b = 20;
int c = a + b * 5;//*优先级高
int c = a + b + 5;//优先级一样看结合性,+号结合性从左到右
return 0;
}
演算子の優先順位、結合性、および評価の順序を知っていると、式の一意の計算パスを見つけることが常に可能であるとは限りません。
a*b+c*d+e*f
无法知道是怎么样的求值路径,表达式就可能存在问题
int fun()
{
static int count = 1;
return ++count;
}
int main()
{
int answer;
answer = fun() - fun() * fun();
printf("%d\n", answer);//输出多少?
return 0;
}
//不确定,我们只知道* 和- ,*先算,但是不知道fun()函数调用是谁先,结果就有问题,错误代码