【问题标题】:Count bits in character and tally the bits计算字符中的位并计算位
【发布时间】:2015-08-25 22:22:54
【问题描述】:

这只是我的第二节编程课。有30个房间,我们要看看每个房间里有什么,然后统计一下。我已经使用 for 循环遍历了 30 个房间,并且我知道我必须使用一个位计数器来查看每个房间中的内容。我不知道如何计算一个单词中的位数。以下是示例输入/输出以及我目前的代码。

示例输入:

9   23  @Z

如果键是:

0 gold_bar
1 silver_bar
2 diamond
3 copper_ring
4 jumpy_troll
5 air
6 angry_troll
7 plutonium_troll

线是 9 23 @Z,然后房间在 9,23(字符 Z,二进制:01011010)有项目 1、3、4、6。silver_bar、copper_ring、jumpy_troll、angry_troll

#include <stdio.h>
#include <stdlib.h>
int main()
{
// contains x and y coordinate
 int first, second;
  char third[100];
char Map[30][30];

// map initialization
for(int x=0; x<30; x++){
    for(int y=0; y<30; y++){
        Map[x][y] = '.';
    }
}


while(scanf("%d %d %s",&first, &second, third) != -1) {
    // Condition 1: a zero coordinate
    if (first==0 || second==0) exit(0);
    // Condition 2: coordinate out of range
    if (first<0 || first>30 || second<0 || second>30){
        printf("Error: out of range 0-30!\n");
        exit(1);
    }
// bit counter
    for( int bit_p=0; bit_p<8; bit_p++){

    }

    Map[second-1][first-1] = third[1];


return 0;
}

示例输入:

1   20  @@
2   21  @A
3   22  @#
4   23  @1
5   22  @@
6   22  @@
7   22  @@
8   22  @@
9   23  @Z  Here be trolls � not!
10  23  @+
12  23  @@
13  24  @@
11  22  @@
14  22  @2
15  21  @1
16  20  @@
17  19  @@
18  20  @@
19  19  @@
20  18  @@
21  17  @*
22  16  @*
23  15  @%
0   14  @7
0   gold_bar
1   silver_bar
2   diamond
3   copper_ring
4   jumpy_troll
5   air
6   angry_troll
7   plutonium_troll

样本输出:

6   gold_bar
6   silver_bar
1   diamond
4   copper_ring
4   jumpy_troll
8   air
15  angry_troll
0   plutonium_troll

【问题讨论】:

标签: c bit


【解决方案1】:

单词的各个位不能用 C 直接访问,因此我们必须做其他事情来获取它们。

考虑你的值,它给出了设置的位:

0 gold_bar          00000001B  or 0x01
1 silver_bar        00000010B  or 0x02
2 diamond           00000100B  or 0x04
3 copper_ring       00001000B  or 0x08
4 jumpy_troll       00010000B  or 0x10
5 air               00100000B  or 0x20
6 angry_troll       01000000B  or 0x40
7 plutonium_troll   10000000B  or 0x80

所以通过观察,让我们考虑一下如果我们有以下情况会发生什么:

unsigned char test = 'z'
unsigned char res = test & 0x02

现在正如您所说,“z”的二进制表示为 01111010,如果我们用 2 进行逻辑运算,我们就有:

     z: 01111010B
  0x02: 00000010B
        ----------
        00000010B

所以表达式 test & 0x02 的计算结果为 0x02。那么,我们如何使用它呢?我们可以这样写:

     if((test & 0x02) == 0x02)
         ++cntSilverBars; 

扩展我们拥有的,假设我们有适当定义的变量( cntAuBars 将被声明为 int cntAuBars 并保存发现的金条数量:

     if((test & 0x01) == 0x01)
         ++cntAuBars;
     if((test & 0x02) == 0x02)
         ++cntAgBars;
     if((test & 0x04) == 0x04)
         ++cntDiamonds;
     if((test & 0x08) == 0x08)
         ++cntCuRings;
     if((test & 0x10) == 0x10)
         ++cntJumpyTroll;
     if((test & 0x20) == 0x20)
         ++cntSilverBars;
     if((test & 0x40) == 0x40)
         ++cntAir;
     if((test & 0x80) == 0x80)
         ++cntPuTroll;

虽然上述方法可行,但可以重写为:

int itemCnt[8] = {0};         // array to hold count of items, index is item type
unsigned char test;           // holds contents of room.
int loc;
for(loc = 0; loc < 8; loc++)  // loop over every bit and see if it is set
{
     unsigned char bitPos = 1 << loc;  // generate a bit-mask 
     if((test & bitPos) == bitPos)
          ++itemCnt[loc];
}

例如下面的程序:

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

int main(int argc, char** argv)
{
  unsigned char test = 'z';
  int           items[8] = {0};
  int           loc;
  int           ndx;

  for(loc = 0; loc < 8; loc++)
  {
      unsigned bitPos = 1 << loc;
      if((test & bitPos) ==  bitPos)
          ++items[loc];
  }


  for(ndx = 0; ndx < 8; ndx++)
  {
     printf("%d, ", items[ndx]);
  }

  return 0;
}

可以编译为:gcc -g -ansi -pedantic -Wall temp.c -o temp,运行时产生以下数组(在调试器中查看时):

(gdb) print /t 'z'
$7 = 1111010
(gdb) print items
$8 = {0, 1, 0, 1, 1, 1, 1, 0}

【讨论】:

  • 谢谢!我如何输出数据,所以它是 6 gold_bar 6 silver_bar 1 diamond 4 Copper_ring 4 jumpy_troll 8 air 15anger_troll 0 plutonium_troll?我需要声明变量吗?
  • @janny 数组跟踪事物。金条的数量将包含在数组的第一个元素中( items[0]),只需确保在遍历房间的循环之外声明项目数组
  • 我可能做错了什么,我写了 printf("%d", itemCnt[0]);并且输出只是 00000000000000000000000
  • @janny 添加了代码来展示如何打印出数组。还注意到我在循环中有一个错误(我修复了)
【解决方案2】:

此代码检查一个字符,如果该位置的位为 0,则用值 0 填充 8 个整数的数组,如果该位置的位为 1,则用值 1 填充

char c = 'Z';
int bits[8];
int n;
char aux = c;
for ( n=0; n<8; ++n ) {
  if ( aux & '\1' )
    bits[n] = 1;
  else
    bits[n] = 0;
  aux = aux >> 1;
}

aux &amp; '\1'aux = aux &gt;&gt; 1 是听说过的代码。

'\1' 是 ASCII 码为 1 的字符,因此它在位置 0 的位为 1,所有其他位为 0。当我们对一个字符进行按位与 '\1' 时,如果该字符 a在位位置 0 处为 1,否则我们得到 0。

aux = aux &gt;&gt; 1 会将位向左移动一个位置,以便在下一次操作中,位置 0 的位将是最初位于位置 1 的位。

【讨论】:

    【解决方案3】:

    没有用于累积字中位数的内置函数。对于每个房间,您需要检查 8 位中的每一个,如果设置了该位,则增加相应的计数变量。有很多方法可以做到这一点,但特别是对于你希望尽可能清楚地做到这一点的课程。

    基本思想是您希望将您读入的单词(“第三”,在您的框架中)与一个向上移动到您正在测试的位位置的单个位掩码进行比较。通过将掩码与输入进行比较,并使用 if 语句对其进行测试。我已将一个示例放入您的框架中:

    // bit counter
    for( int bit_p=0; bit_p<8; bit_p++){
        if (third & (1 << bit_p))
            tally[bit_p]++;
    }
    

    常见的部分是结构if (input &amp; MASK) {do_whatever}。一旦您了解了该结构为何有效,您就可以将其应用于许多情况。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-09-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-05
      • 1970-01-01
      相关资源
      最近更新 更多