Получение каждой отдельной цифры из целого числа

Скажем, у меня есть целое число под названием «оценка», которое выглядит так:

int score = 1529587;

Теперь я хочу получить каждую цифру 1, 5, 2, 9, 5, 8, 7 из счета используя побитовые операторы (см. примечание к редактированию ниже).

Я почти уверен, что это можно сделать, поскольку однажды я использовал аналогичный метод для извлечения значений красного, зеленого и синего из шестнадцатеричного значения цвета.

Как бы я это сделал?

Изменить
Это не обязательно должны быть побитовые операторы, я просто подумал, что так будет проще.


person Johannes Jensen    schedule 25.06.2010    source источник
comment
Поскольку я не нашел его в своем личном сборнике битовых операторов (graphics.stanford.edu/~seander /bithacks.html), я не думаю, что это возможно без более глубокой проработки.   -  person phimuemue    schedule 25.06.2010
comment
если они десятичные, вы не можете использовать их побитово. если они шестнадцатеричные, то это возможно. пожалуйста уточни.   -  person Andrey    schedule 25.06.2010


Ответы (10)


Вы используете оператор по модулю:

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

Обратите внимание, что это даст вам цифры в обратном порядке (т.е. сначала младшая значащая цифра). Если вам нужна самая значащая цифра, вам придется сохранить цифры в массиве, а затем прочитать их в обратном порядке.

person Martin B    schedule 25.06.2010
comment
Я почти уверен, что модуль не является побитовым оператором - person Cyril Gandon; 25.06.2010
comment
@ Scorpi0: Нет, это не так ... но нет разумного способа сделать это с помощью побитовых операторов, и я думаю, что это то, что искал ОП. - person Martin B; 25.06.2010
comment
Я думаю, что OP означал шестнадцатеричный, и его можно решить побитовым. - person Andrey; 25.06.2010
comment
@ Андрей, из примера видно, что ОП спрашивает о десятичных цифрах. - person Geoff; 25.06.2010
comment
Это решение предполагает, что оценка ›= 0. Если score<0, то эта функция никогда не завершится. - person Kuai; 01.02.2016
comment
@Kuai Loop завершится, если score изначально меньше 0. Этот ответ, к сожалению, ничего не печатает с score==0. - person chux - Reinstate Monica; 05.05.2017
comment
Цикл do while исправит это - person technosaurus; 02.10.2018

Значения RGB хорошо ложатся на границы битов; десятичные цифры - нет. Я не думаю, что есть простой способ сделать это с помощью побитовых операторов. Вам нужно будет использовать десятичные операторы, такие как по модулю 10 (% 10).

person David M    schedule 25.06.2010
comment
+1 Он прав, десятичные (по основанию 10) числа не разбиваются на биты (по основанию 2), за исключением чисел, являющихся степенью двойки (например, 256 = 2 ^ 8 для цветов). Поскольку 10 не является степенью числа 2, вы не сможете использовать побитовые операторы. - person Geoff; 25.06.2010

Согласен с предыдущими ответами.

Небольшая поправка: есть лучший способ печатать десятичные цифры слева направо, не выделяя дополнительный буфер. Кроме того, вы можете захотеть отобразить нулевой символ, если score равно 0 (цикл, предложенный в предыдущих ответах, ничего не напечатает).

Это требует дополнительного прохода:

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

do
{
    div /= 10;
    printf("%d\n", score / div);
    score %= div;
} while (score);
person valdo    schedule 25.06.2010
comment
Это решение вызывает деление на ноль, когда score равно нулю. - person Shepmaster; 08.01.2017
comment
Это решение также дает сбой из-за переполнения, когда счет ›= ceil (INT_MAX/10,0). Я предоставил решение, которое корректирует весь диапазон [0, UINT_MAX]. - person Britton Kerin; 14.06.2017
comment
Это решение также не работает для любого числа с 0 цифрами в младшей значащей позиции или позициях. Эти нули не печатаются. Исправленное решение, которое я предоставил, также позволяет избежать этой проблемы. - person Britton Kerin; 15.06.2017

Не изобретайте велосипед. C имеет sprintf по какой-то причине.

Поскольку ваша переменная называется score, я предполагаю, что это для игры, в которой вы планируете использовать отдельные цифры счета для отображения числовых глифов в виде изображений. В этом случае sprintf имеет удобные модификаторы формата, которые позволят вам дополнять партитуру нулями, пробелами и т. д. до фиксированной ширины, которую вы, возможно, захотите использовать.

person R.. GitHub STOP HELPING ICE    schedule 26.06.2010
comment
Мне нравится, как вы ТОЧНО проанализировали, для чего я собирался его использовать. Большое спасибо! - person Johannes Jensen; 26.06.2010

Это решение дает правильные результаты во всем диапазоне [0, UINT_MAX] без необходимости буферизации цифр.

Это также работает для более широких типов или типов со знаком (с положительными значениями) с соответствующими изменениями типа.

Такой подход особенно полезен в крошечных средах (например, в загрузчике Arduino), потому что он не приводит к раздуванию всего printf() (когда printf() не используется для вывода демо) и использует очень мало оперативной памяти. Вы можете увидеть значение, просто мигнув одним светодиодом :)

#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;
}
person Britton Kerin    schedule 14.06.2017

Обычно эта проблема решается с использованием модуля числа в цикле или преобразования числа в строку. Для преобразования числа в строку вы можете использовать функцию 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
person PADYMKO    schedule 11.03.2017
comment
itoa нестандартен, и, насколько мне известно, он не реализован ни на одной из основных платформ. - person S.S. Anne; 03.01.2020

Сначала преобразуйте целое число в строку, используя 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';
person Roberto Caboni    schedule 13.03.2021

Я сделал это решение, оно простое, вместо этого я читаю целое число, я читаю строку (массив символов в C), затем пишу с помощью for bucle, код также записывает сумму цифр

// #include<string.h>

scanf("%s", n);
int total = 0;

for (int i = 0; i< strlen(n); i++){
    printf("%c", n[i]);
    total += (int)(n[i]) -48;
}

printf("%d", total);
person fsalazar_sch    schedule 20.07.2020

person    schedule
comment
он не обрабатывает нули в конце, например, 12344540 не будет печатать последнюю цифру 0 - person marknorkin; 05.11.2018
comment
быстрое решение состоит в том, чтобы использовать условное выражение, например, while(score || div ›1) или просто while(div ›1) - person marknorkin; 05.11.2018

person    schedule
comment
вот модифицированная версия того, что будет дополняться нулями 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++; } - person PSP CODER; 19.04.2020
comment
в котором, если num равно 5, а limit равен 4, тогда будет произведено 0005 - person PSP CODER; 19.04.2020