1
移位运算符
在C语言中移位运算符分两种:“左移”运算符<
“右移“运算符>>。
1.1
功能
移位运算符的功能是将一个数的二进制数左移或者右移多少位,空闲出来的位用补齐。
1.2
用法
具体用法是需要被移位的操作数放在移位运算符的左边,移的位数放在操作数右边。
如a=3;则a的二进制值为00000011
将a的二进制左移两位:a<<2,
移位后a结果为: 00001100
将a的二级制右移两位:a>>2,移位后a的结果为:00000000
2 例子
2.1
需求
现在需要编写一个函数,此函数的需求如下:
函数功能
大小写转化,统计1的总个数。
函数通过参数传入一个字符串(全为小写字母)的起始地址,通过对这个地址的操作把该字符串中的小写字母转换为大写字母,并统计每个大写字母对应ASCII码转换为二进制后1出现的总次数。
函数原型
int caculate_student(char*data_buf, int *count);
参数说明
data_buf是指向字符数组地址的指针,该内存包含一串小写字母。字符串长度不超过4096。
count是被写入的参数。就是将所有大写字母对应ASCII码转换为二进制后1出现的总次数。
返回值
0 操作成功;
1 data_buf为空,即data_buf == NULL,此时count写入值为-1,即*count
= -1。
根据需求来编写函数。理解题目要求也是理解需求的一种形式。
2.2
算法决定
(1) 字符型变量所站位数为8, 值的范围为~128 -- 127。
(2) 字符以ASCII的值的二进制形式存在内存中。字符可以当做整形来处理:一个字符对应着一个ASCII值。大写字符 =
小写字符 - 32。
(3)
处理一个数的二进制不是非要将其化为二进制值存入数组中才可处理。可以采用位运算符来操作。因为位运算符就是用来处理二进制运算的。
(4)
由于不知道一个字符的二进制到底是哪几位的值为1,所以可以通过移位的形式将1已到最高位或者最低位再判断最高位或最低位是否为1。
(5)
与运算符'&'只有二进制位同时为1时才为1,判断二进制数某位是否为1时,可设置一个只是此位为1的数来检测。检测的结果为真,则此位为1,否则此位为0。
(6) 如果采用(5)运算的结果为1,则(*count)++。
2.2.1
采用左移运算符来编写函数
如果采用左移运算符来数一个二进制中1的个数,则与每次移位过后的字符进行&运算的数为128(char型变量二进制只最高位为1)
对应C语言函数为:
#include
#include
int caculate_student(char *data_buf, int *count)
{
int i;
int j;
int t;
if(data_buf == NULL){
*count = -1;
return 1;
}
*count = 0;
t = strlen(data_buf);
for(i = 0; i
data_buf[i] -= 32;
if( ( data_buf[i] & 128 ) ){
(*count)++;
}
for(j = 0; j
data_buf[i] = data_buf[i] <
if( ( (data_buf[i] & 128) == 1) ){
(*count)++;
}
}
}
return 0;
}
#include
#include
int caculate_student(char *data_buf, int *count)
{
int i;
int j;
int t;
if(data_buf == NULL){
*count = -1;
return 1;
}
*count = 0;
t = strlen(data_buf);
for(i = 0; i < t; i++){
data_buf[i] -= 32;
if( ( data_buf[i] & 128 ) ){
(*count)++;
}
for(j = 0; j < 8; j++){
data_buf[i] = data_buf[i] << 1;
if( ( (data_buf[i] & 128) == 1) ){
(*count)++;
}
}
}
return 0;
}
此函数根据题目要求编写,首先求得字符串的长度作为循环的次数,再将小写字符转化为大写字符。然后进行最高位如果为1则计数++的操作(避免最高位为1被计漏掉),然后再逐位判断是否为1,只需要判断8次。
但是调用这个程序之后得不到想要的结果,不是算法的问题。是因为执行左移运算的时候,如果将1移到最高位时,此二进制数至少将表示128,而一个char字符型变量的上限值为127。所以,它将不能表示二进制最高位为1的情况,最高位表示符号位,此时的溢出将导致字符的ASSCII变成一个负值。不能得出正确的结果。
2.2.2
用右移运算符编写函数
采用右移运算符才编写函数,则与经移位过后的字符做&运算的值为1(只有最低位为1)
对应的C语言程序为:
#include
#include
int caculate_student(char *data_buf, int *count)
{
int i;
int j;
int t;
if(data_buf == NULL){
*count = -1;
return 1;
}
*count = 0;
t = strlen(data_buf);
for(i = 0; i
data_buf[i] -= 32;
if( ( data_buf[i] & 1 ) ){
(*count)++;
}
for(j = 0; j
data_buf[i] = data_buf[i] >> 1;
if( ( (data_buf[i] & 1) == 1) ){
(*count)++;
}
}
}
return 0;
}
#include
#include
int caculate_student(char *data_buf, int *count)
{
int i;
int j;
int t;
if(data_buf == NULL){
*count = -1;
return 1;
}
*count = 0;
t = strlen(data_buf);
for(i = 0; i < t; i++){
data_buf[i] -= 32;
if( ( data_buf[i] & 1 ) ){
(*count)++;
}
for(j = 0; j < 8; j++){
data_buf[i] = data_buf[i] >> 1;
if( ( (data_buf[i] & 1) == 1) ){
(*count)++;
}
}
}
return 0;
}
这段程序无疑可以得到正确的结果。能统计出data_buf数组里面所有字符二进制数1的个数。因为移位过后不存在数据溢出的问题。
3 总结
首先是感受到了关于二进制问题算法的时候首先要想到的就应该是”位运算符“,用它们会减少很多的算法(从十进制到二进制)。但是也要考虑到经过移位运算符操作过数据后数据是否超出了数据类型的表示范围,如果超出反而也得不到正确的结果。统计二进制数据1的个数无疑采取右移运算符才是合理的。还有就是移位运算符的左移不一定就是表示将元数据2的移位次数方,只是指溢出位不包含1的情形下。