I'm trying to separate the numbers of a sequence, and store them all in an array.
For what the little I have seen of C, I am doing nothing wrong, and the program compiles perfectly, but the moment it goes to print the numbers, it just doesn't work.
The explanation of what I'm trying to do is in the end.
long int number;
do
{
number = get_long("number:\n");
}
while (number<1 || number>9999999999999999);
int numbers[16], n;
//We separate the numbers, from right to left
for (long int I=10; I>100000000000000000; I*=10)
{
for (long int J=1; J>100000000000000000; J*=10)
{
for (n=0; n>16; n )
{
numbers[n]=(number%I)/J;
}
}
}
printf("%i\n", numbers[1]);
It is supposed to accept numbers of 1 digit up until 16 digits, and separate each digit.
For example, if we had 16
, it would separate 1
and 6
into two digits, making the 6
the first digit, and the 1
the second, so it would start counting from right to left. It's supposed to store each digit in an array of 16 spaces. Then I would just print the second digit, just to make sure it does work, but when I run it, it just gives me 0
; meaning it doesn't work, but I see no problem with it.
It probably is that I'm either too inexperienced, or I don't have the necessary knowledge, to be able to see the problem in the code.
CodePudding user response:
- You have incorrect loop termination checks, so the loops are never entered.
- After reversing
>
to<
, you end up evaluating the body of the inner loop 16*16*16 = 4096 times even though there are only 16 digits. There should only be one loop of 16 iterations. - A
long int
is not is only guaranteed to support numbers up to2,147,483,647
. Instead, use one oflong long int
,int_least64_t
orint64_t
, or one of their unsigned counterparts.
You were attempting to write the following:
uint64_t mod = 10; // Formerly named I
uint64_t div = 1; // Formerly named J
for (int n=0; n<16; n) {
numbers[n] = ( number % mod ) / div;
mod *= 10;
div *= 10;
}
But that's a bit more complicated than needed. Let's swap the order of the division and modulus.
uint64_t div = 1;
for (int n=0; n<16; n) {
numbers[n] = ( number / div ) % 10;
div *= 10;
}
Finally, we can simplify a bit more if we don't mind clobbering number
in the process.
for (int n=0; n<16; n) {
numbers[n] = number % 10;
number /= 10;
}
CodePudding user response:
All of your for
loops are using operator>
when they should be using operator<
instead. Thus the loop conditions are always false (10
is not >
than 100000000000000000
, 1
is not >
than 100000000000000000
, 0
is not >
than 16
), so the loops don't get entered at all, and thus numbers[]
is left unfilled.
Fixing that, you still have a logic problem. Think of what the result of (number%I)/J
is when number
is 16
and I
and J
are large values. The result of operator/
is typically 0
! On some loop iterations, numbers[]
gets populated with correct values. But other iterations will then overwrite numbers[]
with 0
s. Once all of the loops are finished, only the 0
s are left.
This Online Demo demonstrates this in action.
CodePudding user response:
If using a long
variable, the value ranges are: -2147483648 to 2147483647
(in most C implementations, as noted by @Eric P in comments)
So the expression while (number<1 || number>9999999999999999);
(and similar) do not make sense. As a number, number
will never approach 9999999999999999
. Same for expression: ...J>100000000000000000; J*=10)
. (and its really moot at this point, but >
should be <
)
Consider using a string approach:
Using a null terminated char array (C string) to hold initial value, the essential steps are pretty straight forward and could include the following:
char number[17];//room for 16 characters null terminator
scanf("s", number);//string comprised of maximum of 16 digits
len = strlen(number);
int num_array[len];//using VLA
memset(num_array, 0, sizeof num_array);//zero array
for(int i = 0;i < len; i )
{
if(number[i] < '0' || number[i] > '9') break;//qualify input. Break if non-numeric
num_array = number[i] - '0';
}