程序运行结果
int a, b, c;
a = 5;
c = ++a;
b = ++c, c++, ++a, a++;
b += a++ + c;
printf("a = %d b = %d c = %d\n", a, b, c);
line3:c=6,a=6;
line4:(逗号表达式,从左向右计算,结果为最后一个表达式)c=8,a=8,b=6(后置)
line5:a=8,c=8,+=优先级最低,先计算 a++ +c = 16,然后a自增1,b = 17 + 6 = 23。
计算二进制中1的个数
前面讲操作符的时候讲了一种计算二进制1的个数的方式,用移位操作符和位操作符进行判断,还有两种方式也可以计算二进制中1的个数。
除余法
整数除以2的本质是将操作数的二进制向右移动一位,等价于>>操作符,而%2则可以判断二进制的最后一位是否为1,因为奇数最低的二进制位必为1.(2^0)
int count_bit(unsigned int m)
{int count = 0;while (m){if (m % 2 == 1)count++;m /= 2;}return count;
}
需要注意,计算负数需要传无符号整形,否则会导致计算不准确。
n&(n-1)法
每进行一次n&n-1的操作都会消去一个1:
n: 10010n-1: 10001
n&n-1: 10000
n-1: 01111
n&n-1: 00000
可以发现,我们只用了两次就得到了1的个数,通过观察,n-1会将最左边的1变成0,在进行&操作时就会将它变为0,是性能最高的方法。
int count_bit(int m)
{int count = 0;while (m){ m = m & (m - 1);count++;}return count;
}
求两个数二进制不同的个数
移位法
移位法没什么好说的,用& , | 或^都可以比较具体二进制位是否相同。
int count_diff_bit(int m, int n)
{int i = 0;int count = 0;for (i = 0; i < 32; i++){if ((m >> i) & 1 != (n >> i) & 1)count++;}return count;
}
异或法
相异为1,再通过刚才我们提到的n&(n-1)法可以直接计算出1的个数就是不同的个数。
int count_diff_bit(int m, int n)
{int count = 0;int ret = m ^ n;while (ret){ret = ret & (ret - 1);count++;}return count;
}
相同怎么办?32减去1的个数就行了呗!
程序运行结果
int i;
int main()
{i--;if (i > sizeof(i)){printf(">\n");}else{printf("<\n");}return 0;
}
这里有个隐藏知识点就是全局变量或静态变量未初始化时默认为0,局部变量一般初始化为随机值。
显然-1是不可能大于一个正数的,但sizeof是无符号类型,用于计算内存大小,在进行比较时算数优先级低的int类型会被转换成unsigned int进行比较,此时-1被当作一个很大的正数来看待,所以会输出'>’。
上三角判定
上三角矩阵判定_牛客题霸_牛客网
先打印矩阵,下三角要遍历所有行,选择遍历列,以对角线为结束条件(j<i),设置一个开关默认为1,当遇到0时利用goto语句跳出多层循环的特点打印"NO",否则打印1。
int n;scanf("%d", &n);int arr[n][n];int i = 0;for (i = 0; i < n; i++){int j = 0;for (j = 0; j < n; j++){scanf("%d", &arr[i][j]);}}int flag = 1;for (i = 0; i < n; i++){int j = 0;for (j = 0; j < i; j++){if (arr[i][j] != 0){flag = 0;goto end;}}}
end:if (flag == 0)printf("NO\n");else printf("YES\n");
注意没有执行goto end这一语句时仍然会执行end:后的语句。
进制转换
小乐乐与进制转换_牛客题霸_牛客网
- 我们都知道10进制转换为6进制要先进行取余操作:
6%6 = 0
- 再进行除法:
6/6 = 1
1做为新的操作数重复以上操作就能得到6进制的形式,可以看出结果是逆序的,我们可以考虑用递归的形式。
常规做法
#include <stdio.h>
int main()
{int n = 0;int arr[40] = {0};int i = 0;scanf("%d", &n);while(n){arr[i++] = n%6;n/=6;}for(i--; i>=0; i--){printf("%d", arr[i]);}return 0;
}
利用数组接收每一个倒序的6进制数,再逆序打印就是对应的结果。
递归
void six_swap(int n)
{if(n>0){six_swap(n/6);printf("%d",n%6);}
}
int main()
{int a;scanf("%d", &a);six_swap(a);
}
删除指定数字
序列中删除指定数字_牛客题霸_牛客网
思路:遍历数组,将不为删除的数字放入原数组,跳过需要删除的数组。
当然,也可以直接跳过删除的数字打印,算是一种取巧的做法。
#include <stdio.h>int main()
{int num;scanf("%d", &num);int arr[50] = { 0 };//数组大小0<m<50int i = 0;for (i = 0; i < num; i++){scanf("%d", &arr[i]);}int del;scanf("%d", &del);//创建一个新的变量接收不需删除的元素int j = 0;for (i = 0; i < num; i++){if (arr[i] != del){arr[j] = arr[i];j++;}}for (i = 0; i < j;i++){printf("%d ", arr[i]);//打印新的数组}/*for (i = 0; i < num; i++){if(arr[i]!=del)printf("%d",arr[i]);}选择性忽略做法*/return 0;
}
小乐乐走台阶
小乐乐走台阶_牛客题霸_牛客网
两种走法,第一次走一步还有n-1步,第一次走2步还有n-2步,第二次可以选择走一步(n-2 || n-3)或者两步(n-3 || n-4).......
以3为例, 每一层有两种选择,每条支路相加就是所有的走法了。
#include <stdio.h>
int Fab_sta(int x)
{if (x <= 2)return x;else{return Fab_sta(x-1) + Fab_sta(x-2);}
}
int main()
{int a;scanf("%d",&a);printf("%d",Fab_sta(a));return 0;
}