There are a number of ways you can approach parsing the input of digits into groups of digits to be checked as prime. A very straight-forward approach is to read the digits into a C-string and then convert the groups of digits desired into integer values. That process can also be done a number of different ways. One instructive way is simply to manually handle grouping the number of desired digits to check and manually converting each group of digits to an integer value to check if prime.
Whenever you are reading input from the user, you are encourage to read a line of input at-a-time to avoid the pitfalls inherent in a formatted-read using scanf()
(matching-failures and characters left unread in stdin
just waiting to bite you on your next input --> which is the reason for the infinite-loop discussed below your other answer) Reading input with fgets()
into a sufficiently sized buffer (character array) ensures are characters are read and nothing remains unread in stdin
.
So long as you are not on an embedded system or microcontroller, C provides the constant BUFSIZ
which you can use to size your character array, that is sufficient for most inputs you will encounter. In your case two arrays are needed, a separate buffer to hold the digits you will group and convert, and a second general buffer to take the other (B
) input with. You can declare your buffers and read the digits with something similar to the following:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAXDIGITS BUFSIZ
...
int main (void) {
char buf[MAXDIGITS], /* general input buffer */
digits[MAXDIGITS]; /* buffer to hold digits */
int ndigits = 0; /* digits to separate and test */
/* read/validate input A */
fputs ("enter number : ", stdout);
if (!fgets (digits, sizeof digits, stdin)) {
puts ("(user canceled input)");
return 0;
}
digits[strcspn (digits, "\n")] = 0; /* trim trailing '\n' */
...
(note: fgets()
reads and includes the '\n'
generated by the user pressing Enter. A simple way to remove it is to overwrite the '\n'
character with 0
-- the nul-terminating character. strcspn()
provides an efficient manner for doing so as shown above)
Since you are reading digits
, you will want to check that the input is comprised of all digits. You can write a simple function to check if each character entered isdigit()
with the function (or macro) provided in ctype.h
, e.g.
/* simple function checks if s is composed of all digits,
* returns 1 if so, 0 otherwise.
*/
int all_digits (const char *s)
{
int i = 0;
if (!*s || *s == '\n') { /* check empty-string or empty-line */
return 0;
}
for (; s[i]; i++) { /* loop over each digit */
if (!isdigit((unsigned char)s[i])) {
break;
}
}
return !s[i]; /* end-of-string */
}
If the user input into digits
is all-digits, you can proceed to take the second input of the number of digits to group together to check for prime. The approach is the same, read with fgets()
into buf
and then convert the number to int
and validate the number represents a group-size that is possible given the number of digits in digits
, e.g.
if (!all_digits (digits)) { /* validate input all digits */
fputs ("error: invalid integer input.\n", stderr);
return 1;
}
/* read / validate input B */
fputs ("combine ndigits : ", stdout);
if (!fgets (buf, sizeof buf, stdin)) {
puts ("(user canceled input)");
return 0;
}
/* convert string to int / validate */
if (sscanf (buf, "%d", &ndigits) != 1) {
fputs ("error: invalid integer input.\n", stderr);
return 1;
}
/* validate the number of digits to combine is possible */
if (ndigits <= 0 || (size_t)ndigits > strlen (digits)) {
fputs ("error: requested combination of digits not possible.\n",
stderr);
return 1;
}
With both inputs taken and the number of digits ndigits
to group validated, you can convert your groups to int
and check for prime. A simple manual way to do so is to loop over digits
beginning with the index ndigits - 1
and looping ndigits
times for each group manually converting the digits to int
. Only positive values of the groupings are considered, which reduces the task to:
/* loop starting at ndigits digit, combine every ndigits digits into int
* (only positive combinations are considered)
*/
for (int i = ndigits - 1; digits[i]; i++) {
int j = i, /* index for scanning over digits to separate */
n = ndigits, /* copy of number of digits to separate */
num = 0, /* separated number */
mult = 1; /* digit multiplier */
while (n--) { /* loop ndigits times */
num += mult * (digits[j--] - '0'); /* add mult * value to num */
mult *= 10; /* increment mult by 10 */
}
printf (" %*d\n", ndigits, num); /* (optional) output of num */
/** check if num is prime here **/
}
That's it. Checking for prime is left to you. The input, grouping and conversion of the group to int
can be checked by printing each grouping that would be checked for prime.
Example Use/Output
Putting the code together (a complete source is provided at the end), compiling and running your would get:
$ ./bin/group-digits
enter number : 1234
combine ndigits : 1
1
2
3
4
Groupings of two:
$ ./bin/group-digits
enter number : 1234
combine ndigits : 2
12
23
34
Groupings of three:
$ ./bin/group-digits
enter number : 1234
combine ndigits : 3
123
234
Groupings of four:
$ ./bin/group-digits
enter number : 1234
combine ndigits : 4
1234
What about a grouping of five with four-digits?
$ ./bin/group-digits
enter number : 1234
combine ndigits : 5
error: requested combination of digits not possible.
What about a larger string of digits, that itself exceeds the size of int
, but so long as the group-size is within the size of int
, there is no reason that wouldn't work:
$ ./bin/group-digits
enter number : 12345678901234567890
combine ndigits : 4
1234
2345
3456
4567
5678
6789
7890
8901
9012
123
1234
2345
3456
4567
5678
6789
7890
(note: 0123
is properly converted to 123
instead of an octal value representing 83
)
Complete Source for Example
The complete combined source code for the example for easy reference is:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAXDIGITS BUFSIZ
/* simple function checks if s is composed of all digits,
* returns 1 if so, 0 otherwise.
*/
int all_digits (const char *s)
{
int i = 0;
if (!*s || *s == '\n') { /* check empty-string or empty-line */
return 0;
}
for (; s[i]; i++) { /* loop over each digit */
if (!isdigit((unsigned char)s[i])) {
break;
}
}
return !s[i]; /* end-of-string */
}
int main (void) {
char buf[MAXDIGITS], /* general input buffer */
digits[MAXDIGITS]; /* buffer to hold digits */
int ndigits = 0; /* digits to separate and test */
/* read/validate input A */
fputs ("enter number : ", stdout);
if (!fgets (digits, sizeof digits, stdin)) {
puts ("(user canceled input)");
return 0;
}
digits[strcspn (digits, "\n")] = 0; /* trim trailing '\n' */
if (!all_digits (digits)) { /* validate input all digits */
fputs ("error: invalid integer input.\n", stderr);
return 1;
}
/* read / validate input B */
fputs ("combine ndigits : ", stdout);
if (!fgets (buf, sizeof buf, stdin)) {
puts ("(user canceled input)");
return 0;
}
/* convert string to int / validate */
if (sscanf (buf, "%d", &ndigits) != 1) {
fputs ("error: invalid integer input.\n", stderr);
return 1;
}
/* validate the number of digits to combine is possible */
if (ndigits <= 0 || (size_t)ndigits > strlen (digits)) {
fputs ("error: requested combination of digits not possible.\n",
stderr);
return 1;
}
/* loop starting at ndigits digit, combine every ndigits digits into int
* (only positive combinations are considered)
*/
for (int i = ndigits - 1; digits[i]; i++) {
int j = i, /* index for scanning over digits to separate */
n = ndigits, /* copy of number of digits to separate */
num = 0, /* separated number */
mult = 1; /* digit multiplier */
while (n--) { /* loop ndigits times */
num += mult * (digits[j--] - '0'); /* add mult * value to num */
mult *= 10; /* increment mult by 10 */
}
printf (" %*d\n", ndigits, num); /* (optional) output of num */
/** check if num is prime here **/
}
}
If The Groups Are Exclusive
If you intended your groupings to be exclusive, meaning if you had ten-digits, "0123456789"
and wanted groups of five digits, that would provide two exclusive integers 1234
and 56789
, then there are a few easy changes to make.
As a convenience, you can save the length of digits
at the same time you trim the '\n'
from the end, e.g.
...
int main (void) {
char buf[MAXDIGITS], /* general input buffer */
digits[MAXDIGITS]; /* buffer to hold digits */
int ndigits = 0; /* digits to separate and test */
size_t len = 0; /* length of digits */
...
digits[(len = strcspn (digits, "\n"))] = 0; /* trim '\n' save len */
...
You need to ensure len
is divisible by ndigits
, so just add your check to the existing checks for combinations
/* validate the number of digits to combine is possible */
if (ndigits <= 0 || (size_t)ndigits > len || len % ndigits ) {
fputs ("error: requested combination of digits not possible.\n",
stderr);
return 1;
}
Finally adjust your for
loop increment:
/* loop starting at ndigits digit, combine every ndigits digits into int
* (only positive combinations are considered)
*/
for (int i = ndigits - 1; digits[i]; i += ndigits) {
...
Modified Example Use / Output
Now only exclusive ranges of digits are considered for the check against prime:
./bin/group-digits2
enter number : 12345678901234567890
combine ndigits : 4
1234
5678
9012
3456
7890
Or by groups of 5
:
$ ./bin/group-digits2
enter number : 12345678901234567890
combine ndigits : 5
12345
67890
12345
67890
If len
isn't divisible by ndigits
:
$ ./bin/group-digits2
enter number : 12345678901234567890
combine ndigits : 6
error: requested combination of digits not possible.
Let me know if you have questions.