How do I parse a string of numbers into a array of integers?
I have been struggling with this for a while and figured I might as well ask for help instead of banging my head harder into a wall.
So let's say you have the string "10 10 10 4 4 4 9 9 9 2"
and you want to go through it, take out the numbers one by one and add it to an array of integers to use.
I have prototyped A LOT and keep making more work for myself than is necessary. At first I was using strtok()
but then people said that was deprecated and it would be easier to use strsep()
How would I go about doing this?
Any help would be greatly appreciated!
My function seems to always return an int array full of zeros. Why is this?
int *parse_line(char *line){
char sNumArray[MAX];
strcpy(sNumArray, line);
char *tokens = NULL;
int *numbers = malloc(sizeof(int) * MAX);
tokens = strtok(sNumArray, " ");
for(int i = 0; ; i++) {
numbers[i] = atoi(tokens);
printf("%d n", atoi(tokens));
tokens = strtok(NULL, " ");
if (tokens == NULL)
break;
}
return numbers;
}
These are my variables I define in the main and call my function with...
int *skyline;
skyline = parse_line(line);
for (int j = 0; j < 100 ; ++j) {
printf("%d n", skyline[j]);
}
c arrays string parsing c99
add a comment |
I have been struggling with this for a while and figured I might as well ask for help instead of banging my head harder into a wall.
So let's say you have the string "10 10 10 4 4 4 9 9 9 2"
and you want to go through it, take out the numbers one by one and add it to an array of integers to use.
I have prototyped A LOT and keep making more work for myself than is necessary. At first I was using strtok()
but then people said that was deprecated and it would be easier to use strsep()
How would I go about doing this?
Any help would be greatly appreciated!
My function seems to always return an int array full of zeros. Why is this?
int *parse_line(char *line){
char sNumArray[MAX];
strcpy(sNumArray, line);
char *tokens = NULL;
int *numbers = malloc(sizeof(int) * MAX);
tokens = strtok(sNumArray, " ");
for(int i = 0; ; i++) {
numbers[i] = atoi(tokens);
printf("%d n", atoi(tokens));
tokens = strtok(NULL, " ");
if (tokens == NULL)
break;
}
return numbers;
}
These are my variables I define in the main and call my function with...
int *skyline;
skyline = parse_line(line);
for (int j = 0; j < 100 ; ++j) {
printf("%d n", skyline[j]);
}
c arrays string parsing c99
1
strsep
is not standard C;strtok
is
– Govind Parmar
Nov 20 at 1:27
Can you post the code that you've tried, and any errors you're getting? I also suggest usingstrtok
overstrsep
, as it's more widely used, and is of course standard C. In fact, you should be able to find a pretty simple tutorial for this online withstrtok
.
– ahota
Nov 20 at 1:33
add a comment |
I have been struggling with this for a while and figured I might as well ask for help instead of banging my head harder into a wall.
So let's say you have the string "10 10 10 4 4 4 9 9 9 2"
and you want to go through it, take out the numbers one by one and add it to an array of integers to use.
I have prototyped A LOT and keep making more work for myself than is necessary. At first I was using strtok()
but then people said that was deprecated and it would be easier to use strsep()
How would I go about doing this?
Any help would be greatly appreciated!
My function seems to always return an int array full of zeros. Why is this?
int *parse_line(char *line){
char sNumArray[MAX];
strcpy(sNumArray, line);
char *tokens = NULL;
int *numbers = malloc(sizeof(int) * MAX);
tokens = strtok(sNumArray, " ");
for(int i = 0; ; i++) {
numbers[i] = atoi(tokens);
printf("%d n", atoi(tokens));
tokens = strtok(NULL, " ");
if (tokens == NULL)
break;
}
return numbers;
}
These are my variables I define in the main and call my function with...
int *skyline;
skyline = parse_line(line);
for (int j = 0; j < 100 ; ++j) {
printf("%d n", skyline[j]);
}
c arrays string parsing c99
I have been struggling with this for a while and figured I might as well ask for help instead of banging my head harder into a wall.
So let's say you have the string "10 10 10 4 4 4 9 9 9 2"
and you want to go through it, take out the numbers one by one and add it to an array of integers to use.
I have prototyped A LOT and keep making more work for myself than is necessary. At first I was using strtok()
but then people said that was deprecated and it would be easier to use strsep()
How would I go about doing this?
Any help would be greatly appreciated!
My function seems to always return an int array full of zeros. Why is this?
int *parse_line(char *line){
char sNumArray[MAX];
strcpy(sNumArray, line);
char *tokens = NULL;
int *numbers = malloc(sizeof(int) * MAX);
tokens = strtok(sNumArray, " ");
for(int i = 0; ; i++) {
numbers[i] = atoi(tokens);
printf("%d n", atoi(tokens));
tokens = strtok(NULL, " ");
if (tokens == NULL)
break;
}
return numbers;
}
These are my variables I define in the main and call my function with...
int *skyline;
skyline = parse_line(line);
for (int j = 0; j < 100 ; ++j) {
printf("%d n", skyline[j]);
}
c arrays string parsing c99
c arrays string parsing c99
edited Nov 20 at 3:59
asked Nov 20 at 1:25
Jak
25
25
1
strsep
is not standard C;strtok
is
– Govind Parmar
Nov 20 at 1:27
Can you post the code that you've tried, and any errors you're getting? I also suggest usingstrtok
overstrsep
, as it's more widely used, and is of course standard C. In fact, you should be able to find a pretty simple tutorial for this online withstrtok
.
– ahota
Nov 20 at 1:33
add a comment |
1
strsep
is not standard C;strtok
is
– Govind Parmar
Nov 20 at 1:27
Can you post the code that you've tried, and any errors you're getting? I also suggest usingstrtok
overstrsep
, as it's more widely used, and is of course standard C. In fact, you should be able to find a pretty simple tutorial for this online withstrtok
.
– ahota
Nov 20 at 1:33
1
1
strsep
is not standard C; strtok
is– Govind Parmar
Nov 20 at 1:27
strsep
is not standard C; strtok
is– Govind Parmar
Nov 20 at 1:27
Can you post the code that you've tried, and any errors you're getting? I also suggest using
strtok
over strsep
, as it's more widely used, and is of course standard C. In fact, you should be able to find a pretty simple tutorial for this online with strtok
.– ahota
Nov 20 at 1:33
Can you post the code that you've tried, and any errors you're getting? I also suggest using
strtok
over strsep
, as it's more widely used, and is of course standard C. In fact, you should be able to find a pretty simple tutorial for this online with strtok
.– ahota
Nov 20 at 1:33
add a comment |
4 Answers
4
active
oldest
votes
I think this will do what you want.
#include "stdafx.h"
#include <stdio.h>
#include <iostream>
#include <math.h>
#include <stdlib.h>
using namespace std;
#define MAX 100
int *parse_line(char *line, int *numInts) {
char sNumArray[MAX];
strcpy(sNumArray, line);
int *numbers = (int *) malloc(sizeof(int) * MAX);
char *tokens = strtok(sNumArray, " ");
for (int i = 0; ; i++) {
numbers[i] = atoi(tokens);
tokens = strtok(NULL, " ");
if (tokens == NULL) {
*numInts = i+1;
break;
}
}
return numbers;
}
int main() {
char *line = "10 10 10 4 4 4 9 9 9 2";
int numIntsExtracted = 0;
int *skyline = parse_line(line, &numIntsExtracted);
for (int j = 0; j < numIntsExtracted; ++j) {
printf("%d n", skyline[j]);
}
return 0;
}
And the output I'm getting after running it.
10
10
10
4
4
4
9
9
9
2
You're the man, it worked perfectly!
– Jak
Nov 20 at 3:22
Actually, I am having issues with this. When I print the int array is full of 0's I will update my code above
– Jak
Nov 20 at 3:55
This fails then the firsttokens == NULL
. Suggestfor(int i = 0; tokens; i++) {
-->for(int i = 0; ; i++) {
and drop theif (tokens == NULL) break;
– chux
Nov 20 at 4:06
@Jak Its working except you don't see it because you are printing all 100 elements of skyline instead of the exact number you extracted. You need to store somewhere the exact number of integers you extracted. Depending on your needs you could store this in a global variable or pass it via output variable to parse_line.
– driftwood
Nov 20 at 12:08
@driftwood I will try this and get back to you. Thank you for all your help
– Jak
Nov 20 at 16:22
|
show 2 more comments
You have three primary options (1) use strtol
in the manner it was intended, using the *endptr
parameter to advance the current read position within the string to one past the last digit converted, or (2) pass to sscanf
utilizing the "%n"
specifier to report the number of characters used in the conversion to int
(or whatever type) and using that value to advance the read position in the same manner; or (3) tokenizing the string with strtok
and then using strtol
(as atoi
should not be used as it provides absolutely zero error checking). There really isn't any need to use both strtok
and strtol
as strtol
already provides a way to advance past the digits converted. You are essentially duplicating what has already by done by strtol
by using a call to strtok
-- but it is a valid way to go.
For instance using strtol
you could do something like the following:
#include <stdio.h>
#include <stdlib.h> /* for strtol */
#include <string.h> /* for strncpy */
#include <errno.h> /* for errno */
#define MAXC 1024 /* constant - max chars in line */
int main (void) {
char str[MAXC] = ""; /* str to hold line, initialized all zero */
while (fgets (str, MAXC, stdin)) { /* read each line of input */
char *p = str, /* pointer for strtol */
*endptr = NULL; /* end pointer for strtol */
while (*p) { /* work down str parsing integer or hex values */
long val = strtol (p, &endptr, 0); /* convert from p */
/* validate conversion */
if (p != endptr) { /* were digits converted? */
if (!errno) { /* if errno 0, successful conversion */
char ascii[MAXC] = ""; /* for string converted */
strncpy (ascii, p, endptr - p); /* copy to ascii */
ascii[endptr-p] = 0; /* nul-terminate ascii */
/* test whether string begins "0x" or "0X", output */
if (*p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X'))
printf ("hex conversion: %-10s %10lu 0x%lxn",
ascii, val, val);
else
printf ("int conversion: %-10s % ldn",
ascii, val);
}
p = endptr; /* advance p to 1-past end of converted string */
}
/* find start of next valid number in str, including (+/-) */
for (; *p; p++) {
if ('0' <= *p && *p <= '9') /* positive value */
break; /* explicitly signed value */
if ((*p == '+' || *p == '-') && '0' <= *(p+1) && *(p+1) <= '9')
break;
}
}
}
return 0;
}
Example Use/Output
$ echo "10 10 10 4 4 4 9 9 9 2" | ./bin/fgets_strtol_any
int conversion: 10 10
int conversion: 10 10
int conversion: 10 10
int conversion: 4 4
int conversion: 4 4
int conversion: 4 4
int conversion: 9 9
int conversion: 9 9
int conversion: 9 9
int conversion: 2 2
or converting all the integers in a messy file, e.g.
Example Input File
$ cat dat/10intmess.txt
8572,;a -2213,;--a 6434,;
a- 16330,;a
- The Quick
Brown%3034 Fox
12346Jumps Over
A
4855,;*;Lazy 16985/,;a
Dog.
11250
1495
Example Use/Output
$ ./bin/fgets_strtol_any <dat/10intmess.txt
int conversion: 8572 8572
int conversion: -2213 -2213
int conversion: 6434 6434
int conversion: 16330 16330
int conversion: 3034 3034
int conversion: 12346 12346
int conversion: 4855 4855
int conversion: 16985 16985
int conversion: 11250 11250
int conversion: 1495 1495
Using sscanf
Similarly, you can use sscanf
, but be mindful, it doesn't provide the level or degree of error handling -- meaning you can only know that it either successfully converted the text or it failed. No in between, no reporting of overflow or underflow through errno
. But still, it along with strtok
are other valid means of parsing integers from a line of text, e.g.
#include <stdio.h>
#include <stdlib.h>
#define MAXC 1024
int main (int argc, char **argv) {
char buf[MAXC] = ""; /* buffer to hold MAXC chars at a time */
int nval = 0; /* total number of integers found */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.n", argv[1]);
return 1;
}
while (fgets (buf, MAXC, fp)) {
char *p = buf; /* pointer to line */
int val, /* int val parsed */
nchars = 0; /* number of chars read */
/* while chars remain in buf and a valid conversion to int takes place
* output the integer found and update p to point to the start of the
* next digit.
*/
while (*p) {
if (sscanf (p, "%d%n", &val, &nchars) == 1) {
printf (" %d", val);
if (++nval % 10 == 0) /* output 10 int per line */
putchar ('n');
}
p += nchars; /* move p nchars forward in buf */
/* find next number in buf */
for (; *p; p++) {
if (*p >= '0' && *p <= '9') /* positive value */
break;
if (*p == '-' && *(p+1) >= '0' && *(p+1) <= '9') /* negative */
break;
}
}
}
printf ("n %d integers found.n", nval);
if (fp != stdin) fclose (fp); /* close file if not stdin */
return 0;
}
Example Use/Output
$ echo "10 10 10 4 4 4 9 9 9 2" | ./bin/fgets_sscanf_int_any_ex
10 10 10 4 4 4 9 9 9 2
10 integers found.
or with messy input
$ echo "1, 2 buckle my shoe, 3, 4..." | ./bin/fgets_sscanf_int_any_ex
1 2 3 4
4 integers found.
Using strtok
would simply be a "front-end" to conversion with strtol
shown in the first example (which provides its own way to tokenizing numeric values). You simply loop over your buffer calling strtok
with delimiters of " n"
(space newline) and then using strtol
to convert the string pointed to. (here you are simply using endptr
to validate digits were converted and ignoring its use to advance past the digits converted. Essentially, strtok
duplicates what is already done by strtok
, but if it makes it easier to understand, and you can live with the duplicate call, it's fine. You could do something like the following.
while (fgets (buf, MAXC, fp)) {
char *p = buf; /* pointer to buf to use with strtok */
/* 1st call using buffer, all remaining calls using NULL */
for (p = strtok (p, " n"); p; p = strtok (NULL, " n")) {
errno = 0; /* reset errno */
char *endptr; /* end pointer */
long tmp = strtol (p, &endptr, 0); /* convert using long */
if (p != endptr) { /* validate digits converted */
/* now validate value within range of int */
if (!errno && INT_MIN <= tmp && tmp <= INT_MAX)
/* you have an integer! */
}
else if (tmp == 0)
/* no digits were converted */
}
}
Look things over and let me know if you have further questions.
for (; *p; p++) { if ('0' <= *p && *p <= '9') /* positive value */ break; /* explicitly signed value */ if ((*p == '+' || *p == '-') && '0' <= *(p+1) && *(p+1) <= '9') break; }
could be replaced with} else { p++; }
in first code.
– chux
Nov 20 at 4:01
I found a space in"%d%n"
-->"%d %n"
nicely and quickly skips trailing spaces. Useful when looking for''
.
– chux
Nov 20 at 4:04
1
Ooh, that's a nice improvement. It would also cut down on iterating over whitespace searching for the next numeric value as well. Duly noted.
– David C. Rankin
Nov 20 at 4:27
add a comment |
I like to use the function strtol()
for this, because if you pass it a pointer, it will return the next point to continue parsing. There are also unsigned versions, e.g.: strtoul()
. They are standard since C99. Also strtol()
can parse hexadecimal, and handles errors somewhat better than older functions like atoi()
(which returns 0 on error).
The important part of the code below is the result from strtol()
. When next_number
is un-changed after the call, there is no more input (or an error occurred). The variable ptr
is used to keep track of where the parsing is up to in the string. It's given to strtol()
, which changes next_number
to point to the next element, so then ptr
jumps forward - assigned to next_number
(past the element just parsed), and the process repeats.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *number_str = "10 10 10 4 4 4 9 9 9 2";
char *ptr;
char *next_number;
int numbers[1000];
int number_count = 0;
long num;
next_number = number_str;
do
{
ptr = next_number;
num = strtol(ptr, &next_number, 10);
if (ptr != next_number) // found one
{
numbers[number_count] = (int)num;
printf("Stored %3d into numbers[%d]n", numbers[number_count], number_count);
number_count += 1;
}
} while(ptr != next_number);
return 0;
}
add a comment |
Just use scanf() to get each number one by one in for or while loop.
for i = 0 to n
scanf(“%d”, &num);
Pls refer google or bing search online how it is done with many examples available.
This answer is not in C-syntax.
– Kingsley
Nov 20 at 2:57
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53384946%2fhow-do-i-parse-a-string-of-numbers-into-a-array-of-integers%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
I think this will do what you want.
#include "stdafx.h"
#include <stdio.h>
#include <iostream>
#include <math.h>
#include <stdlib.h>
using namespace std;
#define MAX 100
int *parse_line(char *line, int *numInts) {
char sNumArray[MAX];
strcpy(sNumArray, line);
int *numbers = (int *) malloc(sizeof(int) * MAX);
char *tokens = strtok(sNumArray, " ");
for (int i = 0; ; i++) {
numbers[i] = atoi(tokens);
tokens = strtok(NULL, " ");
if (tokens == NULL) {
*numInts = i+1;
break;
}
}
return numbers;
}
int main() {
char *line = "10 10 10 4 4 4 9 9 9 2";
int numIntsExtracted = 0;
int *skyline = parse_line(line, &numIntsExtracted);
for (int j = 0; j < numIntsExtracted; ++j) {
printf("%d n", skyline[j]);
}
return 0;
}
And the output I'm getting after running it.
10
10
10
4
4
4
9
9
9
2
You're the man, it worked perfectly!
– Jak
Nov 20 at 3:22
Actually, I am having issues with this. When I print the int array is full of 0's I will update my code above
– Jak
Nov 20 at 3:55
This fails then the firsttokens == NULL
. Suggestfor(int i = 0; tokens; i++) {
-->for(int i = 0; ; i++) {
and drop theif (tokens == NULL) break;
– chux
Nov 20 at 4:06
@Jak Its working except you don't see it because you are printing all 100 elements of skyline instead of the exact number you extracted. You need to store somewhere the exact number of integers you extracted. Depending on your needs you could store this in a global variable or pass it via output variable to parse_line.
– driftwood
Nov 20 at 12:08
@driftwood I will try this and get back to you. Thank you for all your help
– Jak
Nov 20 at 16:22
|
show 2 more comments
I think this will do what you want.
#include "stdafx.h"
#include <stdio.h>
#include <iostream>
#include <math.h>
#include <stdlib.h>
using namespace std;
#define MAX 100
int *parse_line(char *line, int *numInts) {
char sNumArray[MAX];
strcpy(sNumArray, line);
int *numbers = (int *) malloc(sizeof(int) * MAX);
char *tokens = strtok(sNumArray, " ");
for (int i = 0; ; i++) {
numbers[i] = atoi(tokens);
tokens = strtok(NULL, " ");
if (tokens == NULL) {
*numInts = i+1;
break;
}
}
return numbers;
}
int main() {
char *line = "10 10 10 4 4 4 9 9 9 2";
int numIntsExtracted = 0;
int *skyline = parse_line(line, &numIntsExtracted);
for (int j = 0; j < numIntsExtracted; ++j) {
printf("%d n", skyline[j]);
}
return 0;
}
And the output I'm getting after running it.
10
10
10
4
4
4
9
9
9
2
You're the man, it worked perfectly!
– Jak
Nov 20 at 3:22
Actually, I am having issues with this. When I print the int array is full of 0's I will update my code above
– Jak
Nov 20 at 3:55
This fails then the firsttokens == NULL
. Suggestfor(int i = 0; tokens; i++) {
-->for(int i = 0; ; i++) {
and drop theif (tokens == NULL) break;
– chux
Nov 20 at 4:06
@Jak Its working except you don't see it because you are printing all 100 elements of skyline instead of the exact number you extracted. You need to store somewhere the exact number of integers you extracted. Depending on your needs you could store this in a global variable or pass it via output variable to parse_line.
– driftwood
Nov 20 at 12:08
@driftwood I will try this and get back to you. Thank you for all your help
– Jak
Nov 20 at 16:22
|
show 2 more comments
I think this will do what you want.
#include "stdafx.h"
#include <stdio.h>
#include <iostream>
#include <math.h>
#include <stdlib.h>
using namespace std;
#define MAX 100
int *parse_line(char *line, int *numInts) {
char sNumArray[MAX];
strcpy(sNumArray, line);
int *numbers = (int *) malloc(sizeof(int) * MAX);
char *tokens = strtok(sNumArray, " ");
for (int i = 0; ; i++) {
numbers[i] = atoi(tokens);
tokens = strtok(NULL, " ");
if (tokens == NULL) {
*numInts = i+1;
break;
}
}
return numbers;
}
int main() {
char *line = "10 10 10 4 4 4 9 9 9 2";
int numIntsExtracted = 0;
int *skyline = parse_line(line, &numIntsExtracted);
for (int j = 0; j < numIntsExtracted; ++j) {
printf("%d n", skyline[j]);
}
return 0;
}
And the output I'm getting after running it.
10
10
10
4
4
4
9
9
9
2
I think this will do what you want.
#include "stdafx.h"
#include <stdio.h>
#include <iostream>
#include <math.h>
#include <stdlib.h>
using namespace std;
#define MAX 100
int *parse_line(char *line, int *numInts) {
char sNumArray[MAX];
strcpy(sNumArray, line);
int *numbers = (int *) malloc(sizeof(int) * MAX);
char *tokens = strtok(sNumArray, " ");
for (int i = 0; ; i++) {
numbers[i] = atoi(tokens);
tokens = strtok(NULL, " ");
if (tokens == NULL) {
*numInts = i+1;
break;
}
}
return numbers;
}
int main() {
char *line = "10 10 10 4 4 4 9 9 9 2";
int numIntsExtracted = 0;
int *skyline = parse_line(line, &numIntsExtracted);
for (int j = 0; j < numIntsExtracted; ++j) {
printf("%d n", skyline[j]);
}
return 0;
}
And the output I'm getting after running it.
10
10
10
4
4
4
9
9
9
2
edited Nov 20 at 23:24
answered Nov 20 at 2:57
driftwood
5091720
5091720
You're the man, it worked perfectly!
– Jak
Nov 20 at 3:22
Actually, I am having issues with this. When I print the int array is full of 0's I will update my code above
– Jak
Nov 20 at 3:55
This fails then the firsttokens == NULL
. Suggestfor(int i = 0; tokens; i++) {
-->for(int i = 0; ; i++) {
and drop theif (tokens == NULL) break;
– chux
Nov 20 at 4:06
@Jak Its working except you don't see it because you are printing all 100 elements of skyline instead of the exact number you extracted. You need to store somewhere the exact number of integers you extracted. Depending on your needs you could store this in a global variable or pass it via output variable to parse_line.
– driftwood
Nov 20 at 12:08
@driftwood I will try this and get back to you. Thank you for all your help
– Jak
Nov 20 at 16:22
|
show 2 more comments
You're the man, it worked perfectly!
– Jak
Nov 20 at 3:22
Actually, I am having issues with this. When I print the int array is full of 0's I will update my code above
– Jak
Nov 20 at 3:55
This fails then the firsttokens == NULL
. Suggestfor(int i = 0; tokens; i++) {
-->for(int i = 0; ; i++) {
and drop theif (tokens == NULL) break;
– chux
Nov 20 at 4:06
@Jak Its working except you don't see it because you are printing all 100 elements of skyline instead of the exact number you extracted. You need to store somewhere the exact number of integers you extracted. Depending on your needs you could store this in a global variable or pass it via output variable to parse_line.
– driftwood
Nov 20 at 12:08
@driftwood I will try this and get back to you. Thank you for all your help
– Jak
Nov 20 at 16:22
You're the man, it worked perfectly!
– Jak
Nov 20 at 3:22
You're the man, it worked perfectly!
– Jak
Nov 20 at 3:22
Actually, I am having issues with this. When I print the int array is full of 0's I will update my code above
– Jak
Nov 20 at 3:55
Actually, I am having issues with this. When I print the int array is full of 0's I will update my code above
– Jak
Nov 20 at 3:55
This fails then the first
tokens == NULL
. Suggest for(int i = 0; tokens; i++) {
--> for(int i = 0; ; i++) {
and drop the if (tokens == NULL) break;
– chux
Nov 20 at 4:06
This fails then the first
tokens == NULL
. Suggest for(int i = 0; tokens; i++) {
--> for(int i = 0; ; i++) {
and drop the if (tokens == NULL) break;
– chux
Nov 20 at 4:06
@Jak Its working except you don't see it because you are printing all 100 elements of skyline instead of the exact number you extracted. You need to store somewhere the exact number of integers you extracted. Depending on your needs you could store this in a global variable or pass it via output variable to parse_line.
– driftwood
Nov 20 at 12:08
@Jak Its working except you don't see it because you are printing all 100 elements of skyline instead of the exact number you extracted. You need to store somewhere the exact number of integers you extracted. Depending on your needs you could store this in a global variable or pass it via output variable to parse_line.
– driftwood
Nov 20 at 12:08
@driftwood I will try this and get back to you. Thank you for all your help
– Jak
Nov 20 at 16:22
@driftwood I will try this and get back to you. Thank you for all your help
– Jak
Nov 20 at 16:22
|
show 2 more comments
You have three primary options (1) use strtol
in the manner it was intended, using the *endptr
parameter to advance the current read position within the string to one past the last digit converted, or (2) pass to sscanf
utilizing the "%n"
specifier to report the number of characters used in the conversion to int
(or whatever type) and using that value to advance the read position in the same manner; or (3) tokenizing the string with strtok
and then using strtol
(as atoi
should not be used as it provides absolutely zero error checking). There really isn't any need to use both strtok
and strtol
as strtol
already provides a way to advance past the digits converted. You are essentially duplicating what has already by done by strtol
by using a call to strtok
-- but it is a valid way to go.
For instance using strtol
you could do something like the following:
#include <stdio.h>
#include <stdlib.h> /* for strtol */
#include <string.h> /* for strncpy */
#include <errno.h> /* for errno */
#define MAXC 1024 /* constant - max chars in line */
int main (void) {
char str[MAXC] = ""; /* str to hold line, initialized all zero */
while (fgets (str, MAXC, stdin)) { /* read each line of input */
char *p = str, /* pointer for strtol */
*endptr = NULL; /* end pointer for strtol */
while (*p) { /* work down str parsing integer or hex values */
long val = strtol (p, &endptr, 0); /* convert from p */
/* validate conversion */
if (p != endptr) { /* were digits converted? */
if (!errno) { /* if errno 0, successful conversion */
char ascii[MAXC] = ""; /* for string converted */
strncpy (ascii, p, endptr - p); /* copy to ascii */
ascii[endptr-p] = 0; /* nul-terminate ascii */
/* test whether string begins "0x" or "0X", output */
if (*p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X'))
printf ("hex conversion: %-10s %10lu 0x%lxn",
ascii, val, val);
else
printf ("int conversion: %-10s % ldn",
ascii, val);
}
p = endptr; /* advance p to 1-past end of converted string */
}
/* find start of next valid number in str, including (+/-) */
for (; *p; p++) {
if ('0' <= *p && *p <= '9') /* positive value */
break; /* explicitly signed value */
if ((*p == '+' || *p == '-') && '0' <= *(p+1) && *(p+1) <= '9')
break;
}
}
}
return 0;
}
Example Use/Output
$ echo "10 10 10 4 4 4 9 9 9 2" | ./bin/fgets_strtol_any
int conversion: 10 10
int conversion: 10 10
int conversion: 10 10
int conversion: 4 4
int conversion: 4 4
int conversion: 4 4
int conversion: 9 9
int conversion: 9 9
int conversion: 9 9
int conversion: 2 2
or converting all the integers in a messy file, e.g.
Example Input File
$ cat dat/10intmess.txt
8572,;a -2213,;--a 6434,;
a- 16330,;a
- The Quick
Brown%3034 Fox
12346Jumps Over
A
4855,;*;Lazy 16985/,;a
Dog.
11250
1495
Example Use/Output
$ ./bin/fgets_strtol_any <dat/10intmess.txt
int conversion: 8572 8572
int conversion: -2213 -2213
int conversion: 6434 6434
int conversion: 16330 16330
int conversion: 3034 3034
int conversion: 12346 12346
int conversion: 4855 4855
int conversion: 16985 16985
int conversion: 11250 11250
int conversion: 1495 1495
Using sscanf
Similarly, you can use sscanf
, but be mindful, it doesn't provide the level or degree of error handling -- meaning you can only know that it either successfully converted the text or it failed. No in between, no reporting of overflow or underflow through errno
. But still, it along with strtok
are other valid means of parsing integers from a line of text, e.g.
#include <stdio.h>
#include <stdlib.h>
#define MAXC 1024
int main (int argc, char **argv) {
char buf[MAXC] = ""; /* buffer to hold MAXC chars at a time */
int nval = 0; /* total number of integers found */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.n", argv[1]);
return 1;
}
while (fgets (buf, MAXC, fp)) {
char *p = buf; /* pointer to line */
int val, /* int val parsed */
nchars = 0; /* number of chars read */
/* while chars remain in buf and a valid conversion to int takes place
* output the integer found and update p to point to the start of the
* next digit.
*/
while (*p) {
if (sscanf (p, "%d%n", &val, &nchars) == 1) {
printf (" %d", val);
if (++nval % 10 == 0) /* output 10 int per line */
putchar ('n');
}
p += nchars; /* move p nchars forward in buf */
/* find next number in buf */
for (; *p; p++) {
if (*p >= '0' && *p <= '9') /* positive value */
break;
if (*p == '-' && *(p+1) >= '0' && *(p+1) <= '9') /* negative */
break;
}
}
}
printf ("n %d integers found.n", nval);
if (fp != stdin) fclose (fp); /* close file if not stdin */
return 0;
}
Example Use/Output
$ echo "10 10 10 4 4 4 9 9 9 2" | ./bin/fgets_sscanf_int_any_ex
10 10 10 4 4 4 9 9 9 2
10 integers found.
or with messy input
$ echo "1, 2 buckle my shoe, 3, 4..." | ./bin/fgets_sscanf_int_any_ex
1 2 3 4
4 integers found.
Using strtok
would simply be a "front-end" to conversion with strtol
shown in the first example (which provides its own way to tokenizing numeric values). You simply loop over your buffer calling strtok
with delimiters of " n"
(space newline) and then using strtol
to convert the string pointed to. (here you are simply using endptr
to validate digits were converted and ignoring its use to advance past the digits converted. Essentially, strtok
duplicates what is already done by strtok
, but if it makes it easier to understand, and you can live with the duplicate call, it's fine. You could do something like the following.
while (fgets (buf, MAXC, fp)) {
char *p = buf; /* pointer to buf to use with strtok */
/* 1st call using buffer, all remaining calls using NULL */
for (p = strtok (p, " n"); p; p = strtok (NULL, " n")) {
errno = 0; /* reset errno */
char *endptr; /* end pointer */
long tmp = strtol (p, &endptr, 0); /* convert using long */
if (p != endptr) { /* validate digits converted */
/* now validate value within range of int */
if (!errno && INT_MIN <= tmp && tmp <= INT_MAX)
/* you have an integer! */
}
else if (tmp == 0)
/* no digits were converted */
}
}
Look things over and let me know if you have further questions.
for (; *p; p++) { if ('0' <= *p && *p <= '9') /* positive value */ break; /* explicitly signed value */ if ((*p == '+' || *p == '-') && '0' <= *(p+1) && *(p+1) <= '9') break; }
could be replaced with} else { p++; }
in first code.
– chux
Nov 20 at 4:01
I found a space in"%d%n"
-->"%d %n"
nicely and quickly skips trailing spaces. Useful when looking for''
.
– chux
Nov 20 at 4:04
1
Ooh, that's a nice improvement. It would also cut down on iterating over whitespace searching for the next numeric value as well. Duly noted.
– David C. Rankin
Nov 20 at 4:27
add a comment |
You have three primary options (1) use strtol
in the manner it was intended, using the *endptr
parameter to advance the current read position within the string to one past the last digit converted, or (2) pass to sscanf
utilizing the "%n"
specifier to report the number of characters used in the conversion to int
(or whatever type) and using that value to advance the read position in the same manner; or (3) tokenizing the string with strtok
and then using strtol
(as atoi
should not be used as it provides absolutely zero error checking). There really isn't any need to use both strtok
and strtol
as strtol
already provides a way to advance past the digits converted. You are essentially duplicating what has already by done by strtol
by using a call to strtok
-- but it is a valid way to go.
For instance using strtol
you could do something like the following:
#include <stdio.h>
#include <stdlib.h> /* for strtol */
#include <string.h> /* for strncpy */
#include <errno.h> /* for errno */
#define MAXC 1024 /* constant - max chars in line */
int main (void) {
char str[MAXC] = ""; /* str to hold line, initialized all zero */
while (fgets (str, MAXC, stdin)) { /* read each line of input */
char *p = str, /* pointer for strtol */
*endptr = NULL; /* end pointer for strtol */
while (*p) { /* work down str parsing integer or hex values */
long val = strtol (p, &endptr, 0); /* convert from p */
/* validate conversion */
if (p != endptr) { /* were digits converted? */
if (!errno) { /* if errno 0, successful conversion */
char ascii[MAXC] = ""; /* for string converted */
strncpy (ascii, p, endptr - p); /* copy to ascii */
ascii[endptr-p] = 0; /* nul-terminate ascii */
/* test whether string begins "0x" or "0X", output */
if (*p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X'))
printf ("hex conversion: %-10s %10lu 0x%lxn",
ascii, val, val);
else
printf ("int conversion: %-10s % ldn",
ascii, val);
}
p = endptr; /* advance p to 1-past end of converted string */
}
/* find start of next valid number in str, including (+/-) */
for (; *p; p++) {
if ('0' <= *p && *p <= '9') /* positive value */
break; /* explicitly signed value */
if ((*p == '+' || *p == '-') && '0' <= *(p+1) && *(p+1) <= '9')
break;
}
}
}
return 0;
}
Example Use/Output
$ echo "10 10 10 4 4 4 9 9 9 2" | ./bin/fgets_strtol_any
int conversion: 10 10
int conversion: 10 10
int conversion: 10 10
int conversion: 4 4
int conversion: 4 4
int conversion: 4 4
int conversion: 9 9
int conversion: 9 9
int conversion: 9 9
int conversion: 2 2
or converting all the integers in a messy file, e.g.
Example Input File
$ cat dat/10intmess.txt
8572,;a -2213,;--a 6434,;
a- 16330,;a
- The Quick
Brown%3034 Fox
12346Jumps Over
A
4855,;*;Lazy 16985/,;a
Dog.
11250
1495
Example Use/Output
$ ./bin/fgets_strtol_any <dat/10intmess.txt
int conversion: 8572 8572
int conversion: -2213 -2213
int conversion: 6434 6434
int conversion: 16330 16330
int conversion: 3034 3034
int conversion: 12346 12346
int conversion: 4855 4855
int conversion: 16985 16985
int conversion: 11250 11250
int conversion: 1495 1495
Using sscanf
Similarly, you can use sscanf
, but be mindful, it doesn't provide the level or degree of error handling -- meaning you can only know that it either successfully converted the text or it failed. No in between, no reporting of overflow or underflow through errno
. But still, it along with strtok
are other valid means of parsing integers from a line of text, e.g.
#include <stdio.h>
#include <stdlib.h>
#define MAXC 1024
int main (int argc, char **argv) {
char buf[MAXC] = ""; /* buffer to hold MAXC chars at a time */
int nval = 0; /* total number of integers found */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.n", argv[1]);
return 1;
}
while (fgets (buf, MAXC, fp)) {
char *p = buf; /* pointer to line */
int val, /* int val parsed */
nchars = 0; /* number of chars read */
/* while chars remain in buf and a valid conversion to int takes place
* output the integer found and update p to point to the start of the
* next digit.
*/
while (*p) {
if (sscanf (p, "%d%n", &val, &nchars) == 1) {
printf (" %d", val);
if (++nval % 10 == 0) /* output 10 int per line */
putchar ('n');
}
p += nchars; /* move p nchars forward in buf */
/* find next number in buf */
for (; *p; p++) {
if (*p >= '0' && *p <= '9') /* positive value */
break;
if (*p == '-' && *(p+1) >= '0' && *(p+1) <= '9') /* negative */
break;
}
}
}
printf ("n %d integers found.n", nval);
if (fp != stdin) fclose (fp); /* close file if not stdin */
return 0;
}
Example Use/Output
$ echo "10 10 10 4 4 4 9 9 9 2" | ./bin/fgets_sscanf_int_any_ex
10 10 10 4 4 4 9 9 9 2
10 integers found.
or with messy input
$ echo "1, 2 buckle my shoe, 3, 4..." | ./bin/fgets_sscanf_int_any_ex
1 2 3 4
4 integers found.
Using strtok
would simply be a "front-end" to conversion with strtol
shown in the first example (which provides its own way to tokenizing numeric values). You simply loop over your buffer calling strtok
with delimiters of " n"
(space newline) and then using strtol
to convert the string pointed to. (here you are simply using endptr
to validate digits were converted and ignoring its use to advance past the digits converted. Essentially, strtok
duplicates what is already done by strtok
, but if it makes it easier to understand, and you can live with the duplicate call, it's fine. You could do something like the following.
while (fgets (buf, MAXC, fp)) {
char *p = buf; /* pointer to buf to use with strtok */
/* 1st call using buffer, all remaining calls using NULL */
for (p = strtok (p, " n"); p; p = strtok (NULL, " n")) {
errno = 0; /* reset errno */
char *endptr; /* end pointer */
long tmp = strtol (p, &endptr, 0); /* convert using long */
if (p != endptr) { /* validate digits converted */
/* now validate value within range of int */
if (!errno && INT_MIN <= tmp && tmp <= INT_MAX)
/* you have an integer! */
}
else if (tmp == 0)
/* no digits were converted */
}
}
Look things over and let me know if you have further questions.
for (; *p; p++) { if ('0' <= *p && *p <= '9') /* positive value */ break; /* explicitly signed value */ if ((*p == '+' || *p == '-') && '0' <= *(p+1) && *(p+1) <= '9') break; }
could be replaced with} else { p++; }
in first code.
– chux
Nov 20 at 4:01
I found a space in"%d%n"
-->"%d %n"
nicely and quickly skips trailing spaces. Useful when looking for''
.
– chux
Nov 20 at 4:04
1
Ooh, that's a nice improvement. It would also cut down on iterating over whitespace searching for the next numeric value as well. Duly noted.
– David C. Rankin
Nov 20 at 4:27
add a comment |
You have three primary options (1) use strtol
in the manner it was intended, using the *endptr
parameter to advance the current read position within the string to one past the last digit converted, or (2) pass to sscanf
utilizing the "%n"
specifier to report the number of characters used in the conversion to int
(or whatever type) and using that value to advance the read position in the same manner; or (3) tokenizing the string with strtok
and then using strtol
(as atoi
should not be used as it provides absolutely zero error checking). There really isn't any need to use both strtok
and strtol
as strtol
already provides a way to advance past the digits converted. You are essentially duplicating what has already by done by strtol
by using a call to strtok
-- but it is a valid way to go.
For instance using strtol
you could do something like the following:
#include <stdio.h>
#include <stdlib.h> /* for strtol */
#include <string.h> /* for strncpy */
#include <errno.h> /* for errno */
#define MAXC 1024 /* constant - max chars in line */
int main (void) {
char str[MAXC] = ""; /* str to hold line, initialized all zero */
while (fgets (str, MAXC, stdin)) { /* read each line of input */
char *p = str, /* pointer for strtol */
*endptr = NULL; /* end pointer for strtol */
while (*p) { /* work down str parsing integer or hex values */
long val = strtol (p, &endptr, 0); /* convert from p */
/* validate conversion */
if (p != endptr) { /* were digits converted? */
if (!errno) { /* if errno 0, successful conversion */
char ascii[MAXC] = ""; /* for string converted */
strncpy (ascii, p, endptr - p); /* copy to ascii */
ascii[endptr-p] = 0; /* nul-terminate ascii */
/* test whether string begins "0x" or "0X", output */
if (*p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X'))
printf ("hex conversion: %-10s %10lu 0x%lxn",
ascii, val, val);
else
printf ("int conversion: %-10s % ldn",
ascii, val);
}
p = endptr; /* advance p to 1-past end of converted string */
}
/* find start of next valid number in str, including (+/-) */
for (; *p; p++) {
if ('0' <= *p && *p <= '9') /* positive value */
break; /* explicitly signed value */
if ((*p == '+' || *p == '-') && '0' <= *(p+1) && *(p+1) <= '9')
break;
}
}
}
return 0;
}
Example Use/Output
$ echo "10 10 10 4 4 4 9 9 9 2" | ./bin/fgets_strtol_any
int conversion: 10 10
int conversion: 10 10
int conversion: 10 10
int conversion: 4 4
int conversion: 4 4
int conversion: 4 4
int conversion: 9 9
int conversion: 9 9
int conversion: 9 9
int conversion: 2 2
or converting all the integers in a messy file, e.g.
Example Input File
$ cat dat/10intmess.txt
8572,;a -2213,;--a 6434,;
a- 16330,;a
- The Quick
Brown%3034 Fox
12346Jumps Over
A
4855,;*;Lazy 16985/,;a
Dog.
11250
1495
Example Use/Output
$ ./bin/fgets_strtol_any <dat/10intmess.txt
int conversion: 8572 8572
int conversion: -2213 -2213
int conversion: 6434 6434
int conversion: 16330 16330
int conversion: 3034 3034
int conversion: 12346 12346
int conversion: 4855 4855
int conversion: 16985 16985
int conversion: 11250 11250
int conversion: 1495 1495
Using sscanf
Similarly, you can use sscanf
, but be mindful, it doesn't provide the level or degree of error handling -- meaning you can only know that it either successfully converted the text or it failed. No in between, no reporting of overflow or underflow through errno
. But still, it along with strtok
are other valid means of parsing integers from a line of text, e.g.
#include <stdio.h>
#include <stdlib.h>
#define MAXC 1024
int main (int argc, char **argv) {
char buf[MAXC] = ""; /* buffer to hold MAXC chars at a time */
int nval = 0; /* total number of integers found */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.n", argv[1]);
return 1;
}
while (fgets (buf, MAXC, fp)) {
char *p = buf; /* pointer to line */
int val, /* int val parsed */
nchars = 0; /* number of chars read */
/* while chars remain in buf and a valid conversion to int takes place
* output the integer found and update p to point to the start of the
* next digit.
*/
while (*p) {
if (sscanf (p, "%d%n", &val, &nchars) == 1) {
printf (" %d", val);
if (++nval % 10 == 0) /* output 10 int per line */
putchar ('n');
}
p += nchars; /* move p nchars forward in buf */
/* find next number in buf */
for (; *p; p++) {
if (*p >= '0' && *p <= '9') /* positive value */
break;
if (*p == '-' && *(p+1) >= '0' && *(p+1) <= '9') /* negative */
break;
}
}
}
printf ("n %d integers found.n", nval);
if (fp != stdin) fclose (fp); /* close file if not stdin */
return 0;
}
Example Use/Output
$ echo "10 10 10 4 4 4 9 9 9 2" | ./bin/fgets_sscanf_int_any_ex
10 10 10 4 4 4 9 9 9 2
10 integers found.
or with messy input
$ echo "1, 2 buckle my shoe, 3, 4..." | ./bin/fgets_sscanf_int_any_ex
1 2 3 4
4 integers found.
Using strtok
would simply be a "front-end" to conversion with strtol
shown in the first example (which provides its own way to tokenizing numeric values). You simply loop over your buffer calling strtok
with delimiters of " n"
(space newline) and then using strtol
to convert the string pointed to. (here you are simply using endptr
to validate digits were converted and ignoring its use to advance past the digits converted. Essentially, strtok
duplicates what is already done by strtok
, but if it makes it easier to understand, and you can live with the duplicate call, it's fine. You could do something like the following.
while (fgets (buf, MAXC, fp)) {
char *p = buf; /* pointer to buf to use with strtok */
/* 1st call using buffer, all remaining calls using NULL */
for (p = strtok (p, " n"); p; p = strtok (NULL, " n")) {
errno = 0; /* reset errno */
char *endptr; /* end pointer */
long tmp = strtol (p, &endptr, 0); /* convert using long */
if (p != endptr) { /* validate digits converted */
/* now validate value within range of int */
if (!errno && INT_MIN <= tmp && tmp <= INT_MAX)
/* you have an integer! */
}
else if (tmp == 0)
/* no digits were converted */
}
}
Look things over and let me know if you have further questions.
You have three primary options (1) use strtol
in the manner it was intended, using the *endptr
parameter to advance the current read position within the string to one past the last digit converted, or (2) pass to sscanf
utilizing the "%n"
specifier to report the number of characters used in the conversion to int
(or whatever type) and using that value to advance the read position in the same manner; or (3) tokenizing the string with strtok
and then using strtol
(as atoi
should not be used as it provides absolutely zero error checking). There really isn't any need to use both strtok
and strtol
as strtol
already provides a way to advance past the digits converted. You are essentially duplicating what has already by done by strtol
by using a call to strtok
-- but it is a valid way to go.
For instance using strtol
you could do something like the following:
#include <stdio.h>
#include <stdlib.h> /* for strtol */
#include <string.h> /* for strncpy */
#include <errno.h> /* for errno */
#define MAXC 1024 /* constant - max chars in line */
int main (void) {
char str[MAXC] = ""; /* str to hold line, initialized all zero */
while (fgets (str, MAXC, stdin)) { /* read each line of input */
char *p = str, /* pointer for strtol */
*endptr = NULL; /* end pointer for strtol */
while (*p) { /* work down str parsing integer or hex values */
long val = strtol (p, &endptr, 0); /* convert from p */
/* validate conversion */
if (p != endptr) { /* were digits converted? */
if (!errno) { /* if errno 0, successful conversion */
char ascii[MAXC] = ""; /* for string converted */
strncpy (ascii, p, endptr - p); /* copy to ascii */
ascii[endptr-p] = 0; /* nul-terminate ascii */
/* test whether string begins "0x" or "0X", output */
if (*p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X'))
printf ("hex conversion: %-10s %10lu 0x%lxn",
ascii, val, val);
else
printf ("int conversion: %-10s % ldn",
ascii, val);
}
p = endptr; /* advance p to 1-past end of converted string */
}
/* find start of next valid number in str, including (+/-) */
for (; *p; p++) {
if ('0' <= *p && *p <= '9') /* positive value */
break; /* explicitly signed value */
if ((*p == '+' || *p == '-') && '0' <= *(p+1) && *(p+1) <= '9')
break;
}
}
}
return 0;
}
Example Use/Output
$ echo "10 10 10 4 4 4 9 9 9 2" | ./bin/fgets_strtol_any
int conversion: 10 10
int conversion: 10 10
int conversion: 10 10
int conversion: 4 4
int conversion: 4 4
int conversion: 4 4
int conversion: 9 9
int conversion: 9 9
int conversion: 9 9
int conversion: 2 2
or converting all the integers in a messy file, e.g.
Example Input File
$ cat dat/10intmess.txt
8572,;a -2213,;--a 6434,;
a- 16330,;a
- The Quick
Brown%3034 Fox
12346Jumps Over
A
4855,;*;Lazy 16985/,;a
Dog.
11250
1495
Example Use/Output
$ ./bin/fgets_strtol_any <dat/10intmess.txt
int conversion: 8572 8572
int conversion: -2213 -2213
int conversion: 6434 6434
int conversion: 16330 16330
int conversion: 3034 3034
int conversion: 12346 12346
int conversion: 4855 4855
int conversion: 16985 16985
int conversion: 11250 11250
int conversion: 1495 1495
Using sscanf
Similarly, you can use sscanf
, but be mindful, it doesn't provide the level or degree of error handling -- meaning you can only know that it either successfully converted the text or it failed. No in between, no reporting of overflow or underflow through errno
. But still, it along with strtok
are other valid means of parsing integers from a line of text, e.g.
#include <stdio.h>
#include <stdlib.h>
#define MAXC 1024
int main (int argc, char **argv) {
char buf[MAXC] = ""; /* buffer to hold MAXC chars at a time */
int nval = 0; /* total number of integers found */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.n", argv[1]);
return 1;
}
while (fgets (buf, MAXC, fp)) {
char *p = buf; /* pointer to line */
int val, /* int val parsed */
nchars = 0; /* number of chars read */
/* while chars remain in buf and a valid conversion to int takes place
* output the integer found and update p to point to the start of the
* next digit.
*/
while (*p) {
if (sscanf (p, "%d%n", &val, &nchars) == 1) {
printf (" %d", val);
if (++nval % 10 == 0) /* output 10 int per line */
putchar ('n');
}
p += nchars; /* move p nchars forward in buf */
/* find next number in buf */
for (; *p; p++) {
if (*p >= '0' && *p <= '9') /* positive value */
break;
if (*p == '-' && *(p+1) >= '0' && *(p+1) <= '9') /* negative */
break;
}
}
}
printf ("n %d integers found.n", nval);
if (fp != stdin) fclose (fp); /* close file if not stdin */
return 0;
}
Example Use/Output
$ echo "10 10 10 4 4 4 9 9 9 2" | ./bin/fgets_sscanf_int_any_ex
10 10 10 4 4 4 9 9 9 2
10 integers found.
or with messy input
$ echo "1, 2 buckle my shoe, 3, 4..." | ./bin/fgets_sscanf_int_any_ex
1 2 3 4
4 integers found.
Using strtok
would simply be a "front-end" to conversion with strtol
shown in the first example (which provides its own way to tokenizing numeric values). You simply loop over your buffer calling strtok
with delimiters of " n"
(space newline) and then using strtol
to convert the string pointed to. (here you are simply using endptr
to validate digits were converted and ignoring its use to advance past the digits converted. Essentially, strtok
duplicates what is already done by strtok
, but if it makes it easier to understand, and you can live with the duplicate call, it's fine. You could do something like the following.
while (fgets (buf, MAXC, fp)) {
char *p = buf; /* pointer to buf to use with strtok */
/* 1st call using buffer, all remaining calls using NULL */
for (p = strtok (p, " n"); p; p = strtok (NULL, " n")) {
errno = 0; /* reset errno */
char *endptr; /* end pointer */
long tmp = strtol (p, &endptr, 0); /* convert using long */
if (p != endptr) { /* validate digits converted */
/* now validate value within range of int */
if (!errno && INT_MIN <= tmp && tmp <= INT_MAX)
/* you have an integer! */
}
else if (tmp == 0)
/* no digits were converted */
}
}
Look things over and let me know if you have further questions.
edited Nov 20 at 3:48
answered Nov 20 at 3:37
David C. Rankin
40.1k32647
40.1k32647
for (; *p; p++) { if ('0' <= *p && *p <= '9') /* positive value */ break; /* explicitly signed value */ if ((*p == '+' || *p == '-') && '0' <= *(p+1) && *(p+1) <= '9') break; }
could be replaced with} else { p++; }
in first code.
– chux
Nov 20 at 4:01
I found a space in"%d%n"
-->"%d %n"
nicely and quickly skips trailing spaces. Useful when looking for''
.
– chux
Nov 20 at 4:04
1
Ooh, that's a nice improvement. It would also cut down on iterating over whitespace searching for the next numeric value as well. Duly noted.
– David C. Rankin
Nov 20 at 4:27
add a comment |
for (; *p; p++) { if ('0' <= *p && *p <= '9') /* positive value */ break; /* explicitly signed value */ if ((*p == '+' || *p == '-') && '0' <= *(p+1) && *(p+1) <= '9') break; }
could be replaced with} else { p++; }
in first code.
– chux
Nov 20 at 4:01
I found a space in"%d%n"
-->"%d %n"
nicely and quickly skips trailing spaces. Useful when looking for''
.
– chux
Nov 20 at 4:04
1
Ooh, that's a nice improvement. It would also cut down on iterating over whitespace searching for the next numeric value as well. Duly noted.
– David C. Rankin
Nov 20 at 4:27
for (; *p; p++) { if ('0' <= *p && *p <= '9') /* positive value */ break; /* explicitly signed value */ if ((*p == '+' || *p == '-') && '0' <= *(p+1) && *(p+1) <= '9') break; }
could be replaced with } else { p++; }
in first code.– chux
Nov 20 at 4:01
for (; *p; p++) { if ('0' <= *p && *p <= '9') /* positive value */ break; /* explicitly signed value */ if ((*p == '+' || *p == '-') && '0' <= *(p+1) && *(p+1) <= '9') break; }
could be replaced with } else { p++; }
in first code.– chux
Nov 20 at 4:01
I found a space in
"%d%n"
--> "%d %n"
nicely and quickly skips trailing spaces. Useful when looking for ''
.– chux
Nov 20 at 4:04
I found a space in
"%d%n"
--> "%d %n"
nicely and quickly skips trailing spaces. Useful when looking for ''
.– chux
Nov 20 at 4:04
1
1
Ooh, that's a nice improvement. It would also cut down on iterating over whitespace searching for the next numeric value as well. Duly noted.
– David C. Rankin
Nov 20 at 4:27
Ooh, that's a nice improvement. It would also cut down on iterating over whitespace searching for the next numeric value as well. Duly noted.
– David C. Rankin
Nov 20 at 4:27
add a comment |
I like to use the function strtol()
for this, because if you pass it a pointer, it will return the next point to continue parsing. There are also unsigned versions, e.g.: strtoul()
. They are standard since C99. Also strtol()
can parse hexadecimal, and handles errors somewhat better than older functions like atoi()
(which returns 0 on error).
The important part of the code below is the result from strtol()
. When next_number
is un-changed after the call, there is no more input (or an error occurred). The variable ptr
is used to keep track of where the parsing is up to in the string. It's given to strtol()
, which changes next_number
to point to the next element, so then ptr
jumps forward - assigned to next_number
(past the element just parsed), and the process repeats.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *number_str = "10 10 10 4 4 4 9 9 9 2";
char *ptr;
char *next_number;
int numbers[1000];
int number_count = 0;
long num;
next_number = number_str;
do
{
ptr = next_number;
num = strtol(ptr, &next_number, 10);
if (ptr != next_number) // found one
{
numbers[number_count] = (int)num;
printf("Stored %3d into numbers[%d]n", numbers[number_count], number_count);
number_count += 1;
}
} while(ptr != next_number);
return 0;
}
add a comment |
I like to use the function strtol()
for this, because if you pass it a pointer, it will return the next point to continue parsing. There are also unsigned versions, e.g.: strtoul()
. They are standard since C99. Also strtol()
can parse hexadecimal, and handles errors somewhat better than older functions like atoi()
(which returns 0 on error).
The important part of the code below is the result from strtol()
. When next_number
is un-changed after the call, there is no more input (or an error occurred). The variable ptr
is used to keep track of where the parsing is up to in the string. It's given to strtol()
, which changes next_number
to point to the next element, so then ptr
jumps forward - assigned to next_number
(past the element just parsed), and the process repeats.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *number_str = "10 10 10 4 4 4 9 9 9 2";
char *ptr;
char *next_number;
int numbers[1000];
int number_count = 0;
long num;
next_number = number_str;
do
{
ptr = next_number;
num = strtol(ptr, &next_number, 10);
if (ptr != next_number) // found one
{
numbers[number_count] = (int)num;
printf("Stored %3d into numbers[%d]n", numbers[number_count], number_count);
number_count += 1;
}
} while(ptr != next_number);
return 0;
}
add a comment |
I like to use the function strtol()
for this, because if you pass it a pointer, it will return the next point to continue parsing. There are also unsigned versions, e.g.: strtoul()
. They are standard since C99. Also strtol()
can parse hexadecimal, and handles errors somewhat better than older functions like atoi()
(which returns 0 on error).
The important part of the code below is the result from strtol()
. When next_number
is un-changed after the call, there is no more input (or an error occurred). The variable ptr
is used to keep track of where the parsing is up to in the string. It's given to strtol()
, which changes next_number
to point to the next element, so then ptr
jumps forward - assigned to next_number
(past the element just parsed), and the process repeats.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *number_str = "10 10 10 4 4 4 9 9 9 2";
char *ptr;
char *next_number;
int numbers[1000];
int number_count = 0;
long num;
next_number = number_str;
do
{
ptr = next_number;
num = strtol(ptr, &next_number, 10);
if (ptr != next_number) // found one
{
numbers[number_count] = (int)num;
printf("Stored %3d into numbers[%d]n", numbers[number_count], number_count);
number_count += 1;
}
} while(ptr != next_number);
return 0;
}
I like to use the function strtol()
for this, because if you pass it a pointer, it will return the next point to continue parsing. There are also unsigned versions, e.g.: strtoul()
. They are standard since C99. Also strtol()
can parse hexadecimal, and handles errors somewhat better than older functions like atoi()
(which returns 0 on error).
The important part of the code below is the result from strtol()
. When next_number
is un-changed after the call, there is no more input (or an error occurred). The variable ptr
is used to keep track of where the parsing is up to in the string. It's given to strtol()
, which changes next_number
to point to the next element, so then ptr
jumps forward - assigned to next_number
(past the element just parsed), and the process repeats.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *number_str = "10 10 10 4 4 4 9 9 9 2";
char *ptr;
char *next_number;
int numbers[1000];
int number_count = 0;
long num;
next_number = number_str;
do
{
ptr = next_number;
num = strtol(ptr, &next_number, 10);
if (ptr != next_number) // found one
{
numbers[number_count] = (int)num;
printf("Stored %3d into numbers[%d]n", numbers[number_count], number_count);
number_count += 1;
}
} while(ptr != next_number);
return 0;
}
edited Nov 20 at 3:14
answered Nov 20 at 3:01
Kingsley
2,26711022
2,26711022
add a comment |
add a comment |
Just use scanf() to get each number one by one in for or while loop.
for i = 0 to n
scanf(“%d”, &num);
Pls refer google or bing search online how it is done with many examples available.
This answer is not in C-syntax.
– Kingsley
Nov 20 at 2:57
add a comment |
Just use scanf() to get each number one by one in for or while loop.
for i = 0 to n
scanf(“%d”, &num);
Pls refer google or bing search online how it is done with many examples available.
This answer is not in C-syntax.
– Kingsley
Nov 20 at 2:57
add a comment |
Just use scanf() to get each number one by one in for or while loop.
for i = 0 to n
scanf(“%d”, &num);
Pls refer google or bing search online how it is done with many examples available.
Just use scanf() to get each number one by one in for or while loop.
for i = 0 to n
scanf(“%d”, &num);
Pls refer google or bing search online how it is done with many examples available.
answered Nov 20 at 2:36
anand
802
802
This answer is not in C-syntax.
– Kingsley
Nov 20 at 2:57
add a comment |
This answer is not in C-syntax.
– Kingsley
Nov 20 at 2:57
This answer is not in C-syntax.
– Kingsley
Nov 20 at 2:57
This answer is not in C-syntax.
– Kingsley
Nov 20 at 2:57
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53384946%2fhow-do-i-parse-a-string-of-numbers-into-a-array-of-integers%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
strsep
is not standard C;strtok
is– Govind Parmar
Nov 20 at 1:27
Can you post the code that you've tried, and any errors you're getting? I also suggest using
strtok
overstrsep
, as it's more widely used, and is of course standard C. In fact, you should be able to find a pretty simple tutorial for this online withstrtok
.– ahota
Nov 20 at 1:33