从整数中获取每个单独的数字

35

假设我有一个名为“score”的整数,看起来像这样:

int score = 1529587;

现在我想要做的是从分数中获取每个数字 1、5、2、9、5、8、7,使用位运算符(见下面编辑说明)。

我相信这可以做到,因为我曾经用过类似的方法从十六进制颜色值中提取红、绿、蓝值。

我应该如何做呢?

编辑
不一定要使用位运算符,我只是认为这样更简单。


1
由于我在个人位运算符手册(http://graphics.stanford.edu/~seander/bithacks.html)中没有找到相关内容,所以我认为这可能需要更深入的阐述才能实现。 - phimuemue
如果它们是十进制数,你不能使用位运算来获取它们。如果它们是十六进制,则可能。请指明。 - Andrey
11个回答

68

您使用取模运算符:

while(score)
{
    printf("%d\n", score % 10);
    score /= 10;
}

请注意,这将以相反的顺序给出数字(即最不重要的数字先)。如果您想要按最重要的数字先排序,请将数字存储在数组中,然后以相反的顺序读取它们。


1
我非常确定模运算不是位运算符。 - Cyril Gandon
2
@Scorpi0:不,它不是...但是没有明智的方法使用位运算符来完成这个操作,我认为这就是OP所寻找的。 - Martin B
3
根据示例,很明显OP正在询问十进制数位。 - Geoff
此解决方案假定score >= 0。如果 score<0,那么该函数将永远不会终止。 - Kuai
一个do while循环可以解决这个问题。 - technosaurus
显示剩余2条评论

5

RGB值很好地落在位边界上;而十进制数字不是这样的。我认为没有一种使用位运算符来轻松完成这个任务的方法。你需要使用类似于模10(%10)的十进制运算符。


1
他是正确的,十进制(基数为10)数字不会在位(基数为2)上进行分区,除了像256 = 2 ^ 8这样的2的幂次方数字(用于颜色)。由于10不是2的幂次方,因此您将无法使用位运算符。 - Geoff

4

同意之前的答案。

稍作更正:有一种更好的方法可以从左到右打印小数位,而无需分配额外的缓冲区。此外,如果score为0,您可能希望显示零字符(之前答案中建议的循环不会打印任何内容)。

这需要进行额外的遍历:

int div;
for (div = 1; div <= score; div *= 10)
    ;

do
{
    div /= 10;
    printf("%d\n", score / div);
    score %= div;
} while (score);

1
score 为零时,此解决方案会导致除以零的错误。 - Shepmaster
这个解决方案也会因为分数大于等于 ceil(INT_MAX / 10.0) 而溢出失败。我提供了一个可以在整个范围[0, UINT_MAX]内正确工作的解决方案。 - Britton Kerin
这个解决方案对于任何最低有效位或位置上没有数字的数字也会失败。那些零不会被打印出来。我提供的更正解决方案也避免了这个问题。 - Britton Kerin

4

不要重复造轮子。C语言中有sprintf函数的原因。

由于您的变量被称为“score”,我猜这是一个游戏,您计划使用分数的各个数字来显示数字字形作为图像。在这种情况下,sprintf函数具有方便的格式修饰符,可以让您将分数零填充、空格填充等到固定宽度,您可能需要使用这些修饰符。


1
我喜欢你对我要用它做什么进行了准确的分析。非常感谢! - Johannes Jensen

2
此解决方案在整个范围[0, UINT_MAX]内都能准确地给出结果,而无需缓存数字。
对于更广泛的类型或有适当类型更改的有符号类型(具有正值),它也适用。
这种方法特别适用于小型环境(例如Arduino引导加载程序),因为它不会拉入所有printf()膨胀(当printf()未用于演示输出时),并且使用非常少的RAM。您只需闪烁一个单独的LED即可查看值 :)
#include <limits.h>
#include <stdio.h>

int
main (void)
{
  unsigned int score = 42;   // Works for score in [0, UINT_MAX]

  printf ("score via printf:     %u\n", score);   // For validation

  printf ("score digit by digit: ");
  unsigned int div = 1;
  unsigned int digit_count = 1;
  while ( div <= score / 10 ) {
    digit_count++;
    div *= 10;
  }
  while ( digit_count > 0 ) {
    printf ("%d", score / div);
    score %= div;
    div /= 10;
    digit_count--;
  }
  printf ("\n");

  return 0;
}

1
//this can be easily understandable for beginners     
int score=12344534;
int div;
for (div = 1; div <= score; div *= 10)
{

}
/*for (div = 1; div <= score; div *= 10); for loop with semicolon or empty body is same*/
while(div>1)
{
    div /= 10;
    printf("%d\n`enter code here`", score / div);
    score %= div;
}

它无法处理末尾为零的数字,例如12344540将不会打印最后一个0位数。 - marknorkin
1
快速解决方法是使用条件语句,例如 while(score || div >1) 或者只使用 while(div >1)。 - marknorkin

0
#include<stdio.h>

int main() {
int num; //given integer
int reminder;
int rev=0; //To reverse the given integer
int count=1;

printf("Enter the integer:");
scanf("%i",&num);

/*First while loop will reverse the number*/
while(num!=0)
{
    reminder=num%10;
    rev=rev*10+reminder;
    num/=10;
}
/*Second while loop will give the number from left to right*/
while(rev!=0)
{
    reminder=rev%10;
    printf("The %d digit is %d\n",count, reminder);
    rev/=10;
    count++; //to give the number from left to right 
}
return (EXIT_SUCCESS);}

这是一个修改过的版本,它将使用零进行填充。uint64_t num = 5; uint64_t limit = 4; char * what[limit+1]; what[limit+1] = '\0'; uint64_t remainder = 0; uint64_t rev = 0; int count = 1; int digits = 0; while(num!=0) { remainder=num%10; rev=rev*10+remainder; num/=10; digits++; } if (remainder == 1 && digits != remainder) digits--; if (digits < limit) while(digits!=limit) { rev=rev*10; digits++; } while(rev!=0) { remainder=rev%10; what[count] = "0123456789"[remainder]; rev/=10; count++; } - PSP CODER
如果num为5,limit为4,则会生成0005 - PSP CODER

0

首先使用sprintf将整数转换为字符串,然后对其元素进行任何您想要的操作,这些元素是chars。假设得分是unsigned类型:

unsigned int score = 1529587, i;
char stringScore [11] = { 0 };

sprintf( stringScore, "%d, score );

for( i=0; i<strlen(stringScore); i++ )
    printf( "%c\n", stringScore[i] );

请注意以下几点:
  • 它从最高位开始打印数字
  • stringScore 是11个字符长,假设在您的平台上int大小为4字节,这样最大的整数长度为10个数字。第十一个字符是字符串终止符'\0'
  • sprintf 会替你完成所有工作

每个数字都需要有一个整数吗?

由于我们确定 stringScore 只包含数字,所以转换非常容易。如果 dig 是包含数字的字符,则可以通过以下方式获取相应的整数:

int intDigit = dig - '0';

0
通常,这个问题可以通过在循环中使用数字的模数或将数字转换为字符串来解决。要将数字转换为字符串,您可以使用函数itoa,因此请考虑使用数字的模数在循环中解决该问题。

文件 get_digits.c 的内容

$ cat get_digits.c 

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


// return a length of integer
unsigned long int get_number_count_digits(long int number);

// get digits from an integer number into an array
int number_get_digits(long int number, int **digits, unsigned int *len);

// for demo features
void demo_number_get_digits(long int number);


int
main()
{
    demo_number_get_digits(-9999999999999);
    demo_number_get_digits(-10000000000);
    demo_number_get_digits(-1000);
    demo_number_get_digits(-9);
    demo_number_get_digits(0);
    demo_number_get_digits(9);
    demo_number_get_digits(1000);
    demo_number_get_digits(10000000000);
    demo_number_get_digits(9999999999999);
    return EXIT_SUCCESS;
}


unsigned long int
get_number_count_digits(long int number)
{
    if (number < 0)
        number = llabs(number);
    else if (number == 0)
        return 1;

    if (number < 999999999999997)
        return floor(log10(number)) + 1;

    unsigned long int count = 0;
    while (number > 0) {
        ++count;
        number /= 10;
    }
    return count;
}


int
number_get_digits(long int number, int **digits, unsigned int *len)
{
    number = labs(number);

    // termination count digits and size of a array as well as
    *len = get_number_count_digits(number);

    *digits = realloc(*digits, *len * sizeof(int));

    // fill up the array
    unsigned int index = 0;
    while (number > 0) {
        (*digits)[index] = (int)(number % 10);
        number /= 10;
        ++index;
    }

    // reverse the array
    unsigned long int i = 0, half_len = (*len / 2);
    int swap;
    while (i < half_len) {
        swap = (*digits)[i];
        (*digits)[i] = (*digits)[*len - i - 1];
        (*digits)[*len - i - 1] = swap;
         ++i;
    }

    return 0;
}


void
demo_number_get_digits(long int number)
{
    int *digits;
    unsigned int len;

    digits = malloc(sizeof(int));

    number_get_digits(number, &digits, &len);

    printf("%ld --> [", number);
    for (unsigned int i = 0; i < len; ++i) {
        if (i == len - 1)
            printf("%d", digits[i]);
        else
            printf("%d, ", digits[i]);
    }
    printf("]\n");

    free(digits);
}

使用GNU GCC进行演示

$~/Downloads/temp$ cc -Wall -Wextra -std=c11 -o run get_digits.c -lm
$~/Downloads/temp$ ./run
-9999999999999 --> [9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
-10000000000 --> [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
-1000 --> [1, 0, 0, 0]
-9 --> [9]
0 --> [0]
9 --> [9]
1000 --> [1, 0, 0, 0]
10000000000 --> [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
9999999999999 --> [9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9]

使用LLVM/Clang进行演示

$~/Downloads/temp$ rm run
$~/Downloads/temp$ clang -std=c11 -Wall -Wextra get_digits.c -o run -lm
setivolkylany$~/Downloads/temp$ ./run
-9999999999999 --> [9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
-10000000000 --> [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
-1000 --> [1, 0, 0, 0]
-9 --> [9]
0 --> [0]
9 --> [9]
1000 --> [1, 0, 0, 0]
10000000000 --> [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
9999999999999 --> [9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9]

测试环境

$~/Downloads/temp$ cc --version | head -n 1
cc (Debian 4.9.2-10) 4.9.2
$~/Downloads/temp$ clang --version
Debian clang version 3.5.0-10 (tags/RELEASE_350/final) (based on LLVM 3.5.0)
Target: x86_64-pc-linux-gnu
Thread model: posix

itoa是非标准的,据我所知,在任何主要平台上都没有实现。 - S.S. Anne

0

虽然这个问题已经有答案了,但我还是想插一嘴...

我们将从最不重要的数字开始提取,即以相反的顺序可见。

实际上,我们正在提取基数调色板中的位置或索引。 基数或底数是数字系统的基础。 基数10表示10个数字,基数2表示2个数字,依此类推。

如果我们使用基数16作为示例,我们最终得到的位置超出了我们熟悉的10个“数字”(即10到15,稍后转换为字母A到F)。 无论如何...

int value = 564738291;
int radix = 10;
int array[32]; // At the end = { 5, 6, 4, 7, 3, 8, 2, 9, 1 }
int index = 0; // At the end = 9

if(value == 0) // If value is zero ..
{
    array[index++] = 0; // .. we add a zero, and we're done.
}
else
{
    while(value != 0)
    {
        array[index++] = value % radix; // Copy the value into the array.
        value /= radix;
    }
}

最终,我们的数组将被填充有数字,对于十进制及以下,它们可以直接用作位数,但对于任何大于10的基数,数字将必须转化为所选择基数数字可视化需要使用的“字符”。
例如,在十六进制中,数字可以是0、1、2、3、4、5、6、7、8、9、10、11、12、13、14、15。当打印时,它们可以分别翻译成"0"、"1"、"2"、"3"、"4"、"5"、"6"、"7"、"8"、"9"、"A"、"B"、"C"、"D"、"E"、"F"。因此,数组中的数字仍然是正确的,但它们实际上只是所选择基数内的索引。
关键在于这可以用于提取基数= 2(二进制,您将得到1和0),或任何其他基数的值。
您可以将其与基数20(二十进制)一起使用,然后将这些可能的20个数字转化为Unicode中的玛雅数字(或任何其他也使用基数20的系统),或者为什么不使用巴比伦基数60呢? :)
此外,进制越大,表示一个数字所需的“数字”就越少。这就是为什么最小的进制,即二进制(只有1和0),总是如此长,对于int来说是32(请参见上面伪代码中数组的大小)。
数组中的结果数字也可以用于引用像图像或虚构绘图函数等东西,而不是Unicode。
更多信息:https://en.wikipedia.org/wiki/Positional_notation

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接