24/05/26(1128) 操作符和表达式

给定一个整型数组,有很多元素.

其中只有一个元素出现了一次,其他元素都出现了两次.写一个函数,把这个只出现一次的元素找到.

{1,2,1,2,3}

当前解决方案,针对数字太大,或者为负无法很好处理.等到数据结构"哈希表"更好解决.

运用数组:

#include <stdio.h>
#include <stdlib.h>

int Func(int arr[], int size){
    int numCount[100] = { 0 };
    for (int i = 0; i < size; i++){
        numCount[arr[i]]++;
    }
    for (int i = 0; i < 100; i++){
        if (numCount[i] == 1){
            return numCount[i];
        }
    }
    //数据存在问题,没有只出现一次的数字.
    return 9527;
}

int main(){
    int arr[5] = {1, 2, 1, 2, 3};
    int n = Func(arr,5);
    printf("%d\n",n);
    system("pause");
    return 0;
}

运用异或位:(还是运用异或的特性,如果一个数字接连出现两次就会异或抵消(所以也仅针对当前该数组同一个元素最多出现了两次)).

#include <stdio.h>
#include <stdlib.h>

int Func(int arr[], int size){
    int ret = 0;
    for (int i = 0; i < size; i++){
        ret ^= arr[i];
    }
    return ret;
}

int main(){
    int arr[5] = {1, 2, 1, 2, 3};
    int n = Func(arr,5);
    printf("%d\n",n);
    system("pause");
    return 0;
}

输出:一个整数的二进制数中有多少个"1"

(运用位操作和移位的特性)

#include <stdio.h>
#include <stdlib.h>


int BitOneCount(int num){
    int count = 0;
    for (int i = 0; i < 32; i++){
        if ((num & (1 << i)) != 0){
            count++;
        }
    }
    return count;
}

int main(){

    printf("%d\n",BitOneCount(10));
    system("pause");
    return 0;
}

而 -10 的二进制原码虽然包含3个"1"但计算机中存储负数是使用补码(即原码取反(反码)再加一)

所以当BitOneCount(-10)的输出为 30.

把某个数字的第 N 位设为1: num | (1 << N);

把某个数字的第 N 位设为0: num & ~(1 << N);

赋值操作符

初始化:变量创建的同时,设置初始值.

赋值:变量已经有值了,再修改值.

复合赋值符

+= ^= |= &= <<= >>=

num += 1 -> num = num + 1;

单目操作符

!(逻辑取反),~(按位取反)他俩有什么区别?

int main(){
    int num = 1;
    printf("%x\n",!num);
    printf("%x\n",~num);
    system("pause");
    return 0;
}

逻辑取反就是非零都是真,零就是假.

sizeof 也是单目运算符而不是一个函数.sizeof之后的括号里可以是变量也可以是类型.

int main(){
    int num = 1;
    printf("%d\n",sizeof(int));
    system("pause");
    return 0;
}

思考:这个行为算不算下标越界未定义行为:

int main(){
    int arr[] = {1, 2, 3, 4};
    printf("%d\n",sizeof(arr[100]));
    system("pause");
    return 0;
}

这是sizeof的特性

数组下标越界  => 内存访问越界 => 未定义行为 => 程序运行时访问内存的时候发现是非法内存.

sizeof 是一个运算符,具有一个重要特性,编译期求职.

sizeof(arr[100]) => 程序编译过程中就算出结果了,4.

这个过程不涉及内存访问,也就没有越界,更不是未定义行为.

自增自减 ++ --前置后置是有区别的

int i = 0;

int ret = 0;

ret  = ++i; // ret => 1

ret = i++; // ret => 0

关系操作符

> >= < <= != ==(测试相等)

关系运算符表达式返回值 要么是1,要么是0.(1真0假)

int main(){
    int a = 10;
    int b = 40;
    int c = 30;
    if (a < b < c){
        printf("haha\n");
    }
    else{
        printf("hehe\n");
    }
    system("pause");
    return 0;
}

发现他输出"haha",因为首先判断"a < b"返回1再和 c做比较

所以应该加上逻辑与运算

   if (a < b && b < c);

逻辑操作符: && ||

短路求值:

#include <stdio.h>
#include <stdlib.h>

int main(){
    int i = 0, a = 0, b = 2, c = 3, d = 4;
    i = a++ && ++b && c++ && d++;
    printf("a = %d\n b = %d\n c = %d\n d = %d\n",a,b,c,d);

    system("pause");
    return 0;
}

对于逻辑与运算来说,如果左侧表达式的值已经是假了,此时整个表达式的值已经确定了.右侧表达式不需要求值.

#include <stdio.h>
#include <stdlib.h>

int main(){
    int i = 0, a = 0, b = 2, c = 3, d = 4;
    i = a++ || ++b || c++ || d++;
    printf("a = %d\n b = %d\n c = %d\n d = %d\n",a,b,c,d);

    system("pause");
    return 0;
}

对于逻辑或运算来说,如果左侧表达式的值已经是真了,此时整个表达式的值已经确定了.右侧表达式不需要求值.

后世的大部分编程语言也同样支持短路求值.

条件操作符:

exp1 ?  exp2 : exp3 等价于 if else

int Max(int x, int y){
    //if (x > y){
    //    return x;
    //}
    //return y;
    return x > y ? x : y;
}

条件运算符是所有运算符优先级最低的

表达式求值

隐式类型转换:

范围小的往范围大的类型里转换,但没有char和short

int main(){
    char a = 10;
    char b = 20;
    // a 从 char 转成 int
    // b 从 char 转成 int
    //计算两个int相加,结果还是int
    //int 转为 char赋值给 c
    char c = a + b;
    system("pause");
    return 0;
}

为什么要转换两次?

为了让硬件更简单,软件就要做让步.

CPU从内存读取数据的时候,并不是一个字节一个字节的读,而是四个字节四个字节的读.(整型提升)

类型转换的规则:

1.从大范围的变量转成小范围的变量:进行截断

例如long long 0x0000004411223344

long long -> int

0x11223344

2.从小范围转成大范围

char a = 0x112

char -> int

0x00 00 00 12

前面的几个字节要补符号位

正数补0,负号补1

对于无符号的整数来说,也是补0.

表达式的求值顺序.

#include <stdio.h>
#include <stdlib.h>

int main(){
    int i = 1;
    //如果结果是9,就是2+3+4
    //如果结果是12,就是4+4+4
    int ret = ++i + ++i + ++i;
    printf("%d\n",ret);
    system("pause");
    return 0;
}

++i + ++i + ++i行为是未定义的.代码一定是错的(1.多次2.修改3.无序)

一个表达式中对某个值进行多次修改的时候,由于表达式求值的顺序是不确定的,就导致最终的值是无法确定的.

未定义行为的代码一定是错误代码.最终结果无法确定

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值