此篇操作符只涉及一些容易犯错的问题
1./(除)
想将除数结果为浮点数。
①可将被除数或者除数变成浮点数,也可以两者都加
②如果想在后面加f,那么前面一定是个浮点数,否则编译时会出现问题
int main() {
float a = 6 / 5;//本质还是整数相除得整数
printf("%f\n",a);// 1
float b = 6.0 / 5.0;
printf("%f", b);// 1.2
return 0;
}
2.移位运算符
以负数为例,其实只要知道怎么移,负数的补码如何转化为原码,问题就不大了
1)左移运算符<<(注意开口方向)
int main() {
int a = -7;
//左移
int b = a << 1;
printf("%d",b); // -14
return 0;
}
2)右移运算符>>
①算术右移:右边丢弃,左边补符号位(编译器一般来说,运算的是这种)
②逻辑右移:右边丢弃,左边补0
int main() {
int a = -9;
//右移
int b = a >> 1;
printf("%d",b); //-5
return 0;
}
注意: a的值是没有变的!
计算n二进制的补码有多少个1
判断n是否为2次方的数字
//计算n二进制的补码有多少个1
int countnum1(int n ) {
int i = 0;
int count = 0;
for ( i = 0; i < 32; i++)
{
if (((n >> i) & 1) == 1) {
count++;
}
}
return count;
}
//另解
int countnum1(int n ) {
int count = 0;
while(n){
if(n % == 1){
count++;
}
n /= 2;
}
return count;
}
//判断n是否为2^x次方的数字
//其实2^x的数字,其中只有一个1
// k & (k-1) == 0
int is2cifang(int k) {
int i = 0;
if ((k & (k - 1)) == 0)
{
return 1;
}
else
{
return -1;
}
}
int main() {
int a = 0;
scanf("%d",&a);
if (is2cifang(a) == 1)
{
printf("是2次方的数\n");
}
else
{
printf("不是2次方的数\n");
}
printf("%d", countnum1(a));
return 0;
}
3)异或
计算两个数的二进制不同位的个数有多少个
int countnum1(int n) {
int count = 0;
int i = 0;
while (n)
{
n = n & (n - 1);
count++;
}
return count;
}
int main() {
int a = 0;
int b = 0;
scanf("%d %d",&a,&b);
int ret = a ^ b;
int count = countnum1(ret);
printf("%d",count);
return 0;
}
3.按位取反(要跟左移右移区分好)
附上链接,按位取反是有式子可以记的,看👇
通俗易懂-按位取反、原码反码补码间的转化_LimpidClear的博客-CSDN博客
4. sizeof
sizeof的写法有以下几种
int main() {
int a = -9;
printf("%d",sizeof(a));
printf("%d", sizeof(int));
printf("%d", sizeof a );//由此也可证明它不是函数
//sizeof是操作符,不是函数
//printf("%d", sizeof int);不允许这样写
return 0;
}
注意:sizeof()括号里的表达式是不参与运算的
int main() {
short s = 5;
int a = 6;
printf("%d\n", sizeof(s = a + 2));//以s的字节数为准
//因为跟int类型加一块,short类型还是不能变大,就像你还是你自己
printf("%d", s);// s是值依旧不变,还是5
return 0;
}
注意:sizeof里面传进来的数组参数,本质上是数组的首地址,无论你是short还是其他什么类型,输出的只会是4(32位系统)或8(64位系统),因为地址占用内存的四或八个字节。
void test(int arr[]) {//本质传的是int *arr
//即使上面的[]里面加了10,输出也是地址的内存大小
printf("%d\n", sizeof(arr));
}
void test1(short ch[]) {//本质传的是int *arr
printf("%d\n", sizeof(ch));
}
int main() {
int arr[10] = { 0 };
char ch[10] = { 0 };
//这下面传进来的不是数组!
printf("%d\n",sizeof(arr));//int类型4个字节*10 40
printf("%d\n", sizeof(ch));//short类型1个字节*10 10
test(arr);//因为我的编译器是x86 这两个所以输出都是4
test1(ch);//如果编译器是x64,这两个输出的是8
}
sizeof当中的整型提升
int main() {
char c = 1;
printf("%u\n",sizeof(c));// 1 %u 表示按unsigned int格式输入或输出数据
//全部用%d,结果也一致
printf("%u\n", sizeof(+c));// 4
printf("%u\n", sizeof(-c));// 4
printf("%u\n", sizeof(!c));//这个也是4,但vscode是1,按gcc的来,就是4
return 0;
}
5.前置++跟后置++
这个不过多赘述
前置++:先加加,后使用,跟大家平常想的是一样的
b = a++;
后置++:先使用,后加加。也就是你先用a的时候,它还是它本身的数,你用b的时候,才会加1,如有问题,请指正。
在这里,我想强调的是,面对式子很多个前置++,后置++进行加减运算时,其实这个很“鸡肋”,因为你在Linux系统编译器上跟windows的编译器上,有时候会发生不一致的结果。所以尽量不要用这种进行复合运算。
再讲一下&&跟||还有前后置++的结合
//++与&&
int main() {
int i = 0, a = 0, b = 2, c = 3, d = 4;
i = a++ && ++b && d++;
//先使用a,那么a是0,那么程序已经判断为false,后面就不会执行了,但是a还是要++的
printf("a = %d\nb = %d\nc = %d\nd = %d\n ",a,b,c,d); // 1 2 3 4
printf("%d",i);// 0
return 0;
}
int main() {
int i = 0, a = 1, b = 2, c = 3, d = 4;
i = a++ && ++b && d++;
//为了验证是否都为1,都会执行
printf("a = %d\nb = %d\nc = %d\nd = %d\n ",a,b,c,d); // 2 3 3 5
printf("%d",i);// 1
return 0;
}
//++与||
int main() {
int i = 0, a = 0, b = 2, c = 3, d = 4;
i = a++ || ++b || d++;
//a使用时为0,判断b为2,true,后面就不执行了
printf("a = %d\nb = %d\nc = %d\nd = %d\n ",a,b,c,d); // 1 3 3 4
printf("%d",i);// 1
return 0;
}
习题:
int main() {
int a, b, c;
a = 5;
c = ++a;// c = 6;a = 6
b = ++c, c++, ++a, a++;//c = 8;a = 8; b = 7;
b += a++ + c;//先使用a,让a+c = 16 再加b b= 23; a = 9;
printf("a = %d b = %d c = %d\n",a,b,c);// 9 23 8
return 0;
}
6.取地址&与按位与&区别
按位与:全一才为1,其余情况全为0
7.==与=区别
==数字比较是否相等
而字符串不能用==,用函数strcmp(),strcmp()函数详见👇
C语言简单函数跟递归_LimpidClear的博客-CSDN博客
=赋值
8.逻辑与或,按位与或
逻辑与&&
按位与&
逻辑或||
按位或|
逻辑运算就只是判断是否位真假,按位运算
按位或:全0才为0,其余全为1
9.三目运算符
判断式?真实现的代码:假实现的代码
10.逗号表达式
要从做向右依次计算,但是整个表达式的结果是最后一个表达式的结果
int a = 1;
int b = 2;
int c = 3;
int d = (a = b + 2,c = a -4,b = c+2);
printf("%d\n", d);// 2
printf("%d\n", a);// 4
printf("%d\n", c);// 0
int main() {
//方法都没写,只是一个示例
int a = get_value();
count_value(a);
while (a >0)
{
int a = get_value();
count_value(a);
}
//其实等价于
int a = 0;
while (a = get_value(),count_value(a),a > 0)
{
}
return 0;
}
sizeof跟逗号表达式的结合
int main() {
int arr[] = {1,2,3,(3,4)};//其实就是{1,2,3,4}
printf("%d",sizeof(arr));// 4*4 = 16
return 0;
}
11.访问一个结构的成员
. 结构体.成员名
-> 结构体指针->成员名
struct Book
{
char name[10];
int price;
};
int main() {
struct Book b = {"C",20};//这个struct要加
//结构体变量名.成员名
printf("%s ",b.name);
printf("%d\n", b.price);
//结构体指针->成员名
struct Book* pa = &b;
printf("%s ", pa->name);
printf("%d\n", pa->price);
//用*pa.成员名也行
return 0;
}
12.[]下标引用
下标引用要注意数组越界的问题,例如int[10];
就不可能有int[10] = 2;因为只有0-9