Good evening,
I'm having trouble with an assignement.
Basically we're required to code a program which will calculate the prime factors of a given stdin
. The data may only enter the program through its stdin
, be it throuh an echo
or a < file.txt
. The stream of data will never be greater than 80 characters (they can be numbers or not).
The functions I use in the program are read()
, strotol()
and strtok()
, and the "irrelevant" code flows as follows:
malloc
to allocate 80 initial bytes of memory. int
, through read()
the number of characters read (and I believe, the last \0
). realloc()
so as to save as much memory (I know in this case it's trivial, but oh well...). Now comes the tricky bit:
(n/2)+1
, where n
is the number of characters read in the upper point nº 2. long
with max size the number obtained in point nº 1. numbers[0]
with the result of: strtol(strtok(line, delim), &end, 10)
.Adds 1
to the counter
and enters a while
loop:
while((numbers[counter] = strtol(strtok(NULL, delim), &end, 10)) != NULL) {
if(!*end) {
// Check whether it's 0, 1, negative, prime or extract its factors
}
else {
fprintf(stderr, "\"%s\" is not a non-negative integer", end)
}
counter++;
}
Now, here are some inputs and their outputs:
Input: echo 1 2 3 4 5 6 7 8 9 10 | ./factors
Output:
1
2
3
2 2
5
2 3
7
2 2 2
3 3
2 5
Segmentation Fault (core dumped).
Input ./factors < integers.txt
Where integers contains a COLUMN of integers.
Output:
All the integers are factorised just fine and at the end it prints a:
Segmentation Fault (core dumped).
Input: echo abc 12 13 14 15 | ./factors
Output:
"abc" is not a non-negative integer
13
2 7
3 5
Segmentation Fault (core dumped).
Input: echo -1 -2 -3 -4 -5 | ./factors
Output:
"-1" is not a non-negative integer
"-2" is not a non-negative integer
"-3" is not a non-negative integer
"-4" is not a non-negative integer
"-5" is not a non-negative integer
Input: echo abc abc abc | ./factors
Output:
"abc" is not a non-negative integer
(And does not continue checking).
Input: echo 3 4 0 6 7 | ./factors
Output:
3
2 2
(And does not continue checking).
So as far as I can see, it fails when it encounters a 0
, more than one instance of a non-integer
or basically at the end of a healthy integer
-based stream of data.
Any idea how I could tackle this while and why is it failing so apparently randomly?
I should let you know I'm new to C...
Thank you very much in advanced.
====================================================
EDIT1: As per request, here are the code fragments which generate numbers[]
, and read from stdin
:
char *line;
char *end;
char *delim = " \n";
int charsread, counter;
line = malloc(80);
charsread = read(0, line, 81);
if (charsread == 0) {
return EX_OK;
}
realloc(line, charsread);
maxelem = (charsread / 2) + 1;
long numbers[maxelem];
numbers[0] = strtol(strtok(line, delim), &end, 10);
if (!*end) {
zeroone(numbers[0]);
}
else {
fprintf(stderr, "\"%s\" is not a non-negative integer\n", end);
}
counter = 1;
while [...]
Thank you very much for your insightful response.
In the end I just rewrote the whole thing up since it didn't look as clean as I expected.
Since the manual from strtok
specifies a return value of NULL
if no token could be extracted, this is what I ended up with:
long number;
item = strtok(line, delim);
while (item != NULL) {
number = strtol(item, &rest, 10);
if (*rest == 0) {
zeroOne(number);
}
else {
fprintf(stderr, "\"%s\": not a non-negative int.\n", item);
}
item = strtok(NULL, delim);
}
Seems a cleaner approach and does consider the fact that the returned value from the strtok when it is NULL
is returned BEFORE it tries to enter the while
loop I had before. Then, this morning I came back here and read your response :)
A follow-up question regarding your hard-coded input of a \0
to the line read: Does this mean that my last strtok
actually outputs the \0
token and tries to enter the loop, or does it return a NULL
when it reaches the entity right after my last introduced character?
As a convention, when using read()
(or maybe other reading functions such as fgets()
should I always try to hard-code a \0
to the line read to allow other functions to check for EOL
/ EOF
?
If someone else should be having trouble using any of these functions (strtok
and strtol
) I recommend to check out these two questions posted on this very site:
Regarding strtol
's second argument: Strtol second argument
Regarding strtok
's output: Cannot concatenate strtok's output variable. strcat and strtok