如何返回C中long的结束数字(特别是当它们为0时)

时间:2018-12-06 04:02:13

标签: c math

我一直在解决信用卡问题,但在弄清楚如何提取数字的结尾数字时遇到了麻烦,例如,执行123%10可获得3,123%100可获得23等。但是我遇到的问题是一个数字,例如6310005,其中%10到10000全部返回5,而我希望它返回5,05,005等。Here is a link to the output of findDoubles(378282246310005,15,1)

long* findDoubles(long cardNum, int cardLength, int startIndex)
{
    long length = 0;
    // if starting at the second number, and counting there on
    if(startIndex == 1 )
    {
        length = floor(cardLength/2);
    }
    else
    {
        length = ceil(cardLength/2);
    }
    long *doublesArr = malloc(length);
    for (int i = startIndex; i < length; i++)
    {
        doublesArr[i] = cardNum % (long)pow(10,i);
        printf("\ndoublesArr[%i] = %lu",i, doublesArr[i]);
    }
    return doublesArr;
}

任何帮助将不胜感激,谢谢

3 个答案:

答案 0 :(得分:2)

在我这样说之前,让我强调一下,您 不应将信用卡号存储为整数。

但是...关键是,从模运算中得到余数之后,您需要从初始值中减去它,然后将初始值除以基数。

#include <stdio.h>

int main(void) {
  unsigned long long int CC = 1234123412341234; 
  unsigned long long int temp = CC;
  unsigned short int A[16] = { 0 };
  int i;

  for (i = 0; i < 16; i++) {
    A[15-i] = temp % 10;
    temp = temp - A[15-i];
    temp = temp / 10;
  }

  printf("As an unsigned long long int, the CC number is %llu\n", CC);
  printf("As individual digits in an array, the CC number is ");

  for (i = 0; i < 16; i++) {
    printf("%1d", A[i]);
  }

  printf("\n\n");

  return 0;
}

答案 1 :(得分:1)

处理以startindex开头的部分卡号要容易得多。假设long最多只需要21-chars(包括符号和 nul-终止字符),那么就需要一个具有自动存储持续时间的简单缓冲区。您可以将缓冲区作为参数传递,并只需将字符串内的startindex作为sprintf的字符指针返回(通过对finddoubles的简单调用即可创建)。

一个简单的例子是:

#include <stdio.h>

#define MAXSTR 32   /* max chars for long is 21 */

char *finddoubles (long cardnum, int cardlength, int startindex, char *str)
{
    if (!str) {     /* check valid address for str */
        fputs ("error: str unallocated pointer.\n", stderr);
        return NULL;
    }

    /* validate conversion matches cardlength */
    if (sprintf (str, "%ld", cardnum) != cardlength) {
        fputs ("error: conversion not cardlength chars.\n", stderr);
        return NULL;
    }

    return &str[startindex];    /* return requesting substring at index */
}

int main (void) {

    long num = 6310005;   /* example credit card number */
    int len = 7;          /* length */
    char str[MAXSTR];     /* buffer for conversion - avoids allocation */

    for (int i = 0; i < len; i++)   /* output values for all startindexes */
        printf ("start index: %d  indexed card no.: %s\n",
                i, finddoubles (num, len, i, str));
}

注意:您只需将返回值分配给字符指针(例如char *p = finddoubles (num, len, i, str);即可使用,而不是立即打印该值)

使用/输出示例

$ ./bin/cardnumidx
start index: 0  indexed card no.: 6310005
start index: 1  indexed card no.: 310005
start index: 2  indexed card no.: 10005
start index: 3  indexed card no.: 0005
start index: 4  indexed card no.: 005
start index: 5  indexed card no.: 05
start index: 6  indexed card no.: 5

有很多方法可以做到这一点。最简单的是使用sprintf。由于sprintf是标准库的一部分,因此无需进行自己的转换。仔细研究一下,如果您还有其他问题,请告诉我。

编辑16个字符的Cardnum

如果如评论中所述,信用卡号始终为16个字符,则sprintf的简单填充字段宽度修饰符将确保您为完整的卡号,并进行了以下修改,例如

    ...
    if (sprintf (str, "%016ld", cardnum) != cardlength) {
    ...
    int len = 16;
    ...
    for (int i = 0; i < len; i++)
        printf ("start index: %2d  indexed card no.: %s\n",
        ...

使用/输出示例

$ ./bin/cardnumidx
start index:  0  indexed card no.: 0000000006310005
start index:  1  indexed card no.: 000000006310005
start index:  2  indexed card no.: 00000006310005
start index:  3  indexed card no.: 0000006310005
start index:  4  indexed card no.: 000006310005
start index:  5  indexed card no.: 00006310005
start index:  6  indexed card no.: 0006310005
start index:  7  indexed card no.: 006310005
start index:  8  indexed card no.: 06310005
start index:  9  indexed card no.: 6310005
start index: 10  indexed card no.: 310005
start index: 11  indexed card no.: 10005
start index: 12  indexed card no.: 0005
start index: 13  indexed card no.: 005
start index: 14  indexed card no.: 05
start index: 15  indexed card no.: 5

注意long不能在所有系统上都包含16位数字

@chqrlie在以下评论中针对旧版系统(例如X86中,long的值只有32位,只能从-2147483648 to 2147483647开始,并且不能保存16位。为了解决这个问题,最好使用stdint.h中定义的精确尺寸类型,例如int64_t(对于您的long)或更佳的uint64_t,例如使用带符号数字在这里毫无意义。 inttypes.h中提供了用于精确尺寸类型的相应打印宏。

答案 2 :(得分:0)

  

返回long的结束数字

这只是long的“ mod”(按10的幂)。

要在打印中保留前导零,请将".*" precision 用作printf()的一部分以直接输出,或使用sprintf()保存到字符串

由于抄送号码通常超过10位数字,因此最好使用可以容纳long的更宽的类型,这可能是不够的。 unsigned long long可以处理所有19位数字-至少。

#include <stdio.h>

unsigned long long pow10_ull(unsigned y) {
  unsigned long long z = 1;
  unsigned long long base = 10;
  while (y) {
    if (y % 2) {
      z *= base;
    }
    y /= 2;
    base *= base;
  }
  return z;
}

unsigned long long endDigits(unsigned long long cardNum, int endLength) {
  return cardNum % pow10_ull(endLength);
}

void printEndDigits(unsigned long long cardNum, int cardLength,
    int startIndex) {
  int endLength = cardLength - startIndex;
  printf("%.*llu\n", endLength, endDigits(cardNum, endLength));
}

int main() {
  printEndDigits(378282246310005, 15, 1);
  printEndDigits(378282246310005, 15, 11);
  return 0;
}

输出

78282246310005
0005