There is a string with a line of text. Let's say:
char * line = "Foo|bar|Baz|23|25|27";
I would have to find the numbers.
I was thinking of something like this:
If the given char is a number, let's put it into a temporary char array. (buffer)
If the next character is NOT a number, let's make the buffer a new int.
The problem is... how do I find numbers in a string like this?
(I'm not familiar with C99/gcc that much.)
Compiler used: gcc 4.3 (Environment is a Debian Linux stable.)
I would approach as the following:
Considering '|' as the separator, tokenize the line of text, i.e. split the line into multiple fields.
For each token:
If the token is numeric:
Convert the token to a number
Some library functions that might be useful are strtok, isdigit, atoi.
One possible implementation for the approach suggested in this answer, based on sscanf.
#include <stdio.h>
#include <string.h>
void find_integers(const char* p) {
size_t s = strlen(p)+1;
char buf[s];
const char * p_end = p+s;
int n;
/* tokenize string */
for (; p < p_end && sscanf(p, "%[^|]%n", &buf, &n); p += (n+1))
{
int x;
/* try to parse an integer */
if (sscanf(buf, "%d", &x)) {
printf("got int :) %d\n", x);
}
else {
printf("got str :( %s\n", buf);
}
}
}
int main() {
const char * line = "Foo|bar|Baz|23|25|27";
find_integers(line);
}
Output:
$ gcc test.c && ./a.out
got str :( Foo
got str :( bar
got str :( Baz
got int :) 23
got int :) 25
got int :) 27
Related
I'm trying to make a simple program where you put some text in it and it write back what you just wrote.
For example if I write "Hello World", the program should write me back "Hello World"
How I think it should work is like that :
loop to check if the current character is '\0'
if not print the current character and reallocate 1 more byte of memory
else stop the loop
So it's looks like an easy thing to do but my attempt is not working correctly, for example if you put only a few characters it is going to write you back with no problem but with longer string.. it is not working at all.
I know it is possible using fgets(), but I would like to understand why my version with scanf() isn't working.
(my code)
#include <stdio.h>
#include <stdlib.h>
int main(void){
int mem = 2;
char * str = malloc(mem);
scanf("%s", str);
while (*str != '\0') {
printf("%c", *str);
realloc(str, mem++);
str++;
}
free(str);
return 0;
}
edit : I was thinking that I only did a small mistake but, after reading the comments it looks like there is a lot of things that I did wrong in this tiny program. I'm going make sure that I better understand how C work and retry to do this program later. Thanks for the help!
Your program could be much more simple
#include <stdio.h>
int main() {
char c;
while( scanf("%c", &c) == 1 ) {
printf("%c", c);
}
return 0;
}
If you're going to use scanf for this, you shouldn't use "%s". (You should never use "%s" without a field width, since this will potentially overflow a buffer. Using "%s" is no better that gets().) If you are going to use a variant of "%s", you need to understand that it will ignore whitespace. The following does almost what you want, except for the whitespace issue. If you want to handle whitespace with precision, you cannot use "%s".
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
void * xrealloc(void *buf, size_t num, size_t siz, void *endvp);
int
main(void)
{
size_t cap = 2;
char *end = NULL;
char *str = xrealloc(NULL, cap, sizeof *str, &end);
/*
* Read 1 char at a time, discarding whitespace. This should
* be done with getchar(). If using scanf, a single char
* should be read with "%c". We use "%1s" here only
* because the question is specifically about `%s`.
* Note that %1s will allow scanf to write up to 2 characters into
* *end, so we need to ensure there is space for the terminator.
*/
while( 1 == scanf("%1s", end++) ){
while( end > str + cap - 2 ){
str = xrealloc(str, cap *= 2, sizeof *str, &end);
}
}
fputs(str, stdout);
free(str);
return 0;
}
void *
xrealloc(void *buf, size_t num, size_t siz, void *endvp)
{
char **endp = endvp;
char *b = buf;
ptrdiff_t offset = b && endp && *endp ? *endp - b : 0;
b = realloc(b, num * siz);
if( b == NULL ){
perror("realloc");
exit(EXIT_FAILURE);
}
if( endp != NULL ){
*endp = b + offset;
}
return b;
}
Reading functions' manuals and searching for similar questions is a great method to get things clearer, and undestand the problem you are facing better :)
Try looking at this question: Reading input of unknown length, and particularly at this answer that uses scanf: scanf answer (I did not verify if that works, but it teaches you another method you can use).
How to get string until second symbol through sscanf?
for example:
char *str = "struct1.struct2.struct3.int";
char buf[256] = {0};
sscanf(str, "", buf); //have any format string could get string until second dot?
sscanf get string until second symbol (include one)
How to get string until second symbol through sscanf?
Not generally possible with a single use of sscanf().
Certainly, without a lot of work, a more involved use of sscanf() will work for many input strings, yet fail for select ones1. sscanf() is not the best fit here for this task.
strchr(), strcspn() better suited.
#include <string.h>
#include<stdlib.h>
// Return offset to 2nd needle occurrence
// or end of string, if not found.
size_t foo(const char *haystack, const char *needle) {
size_t offset = strcspn(haystack, needle);
if (haystack[offset]) {
offset++;
offset += strcspn(haystack + offset, needle);
}
return offset;
}
#include <stdio.h>
int main() {
const char *haystack = "struct1.struct2.struct3.int";
printf("<%.*s>\n", (int) foo(haystack, "."), haystack);
}
Output
<struct1.struct2>
1 Consider: "struct1.struct2", "struct1..", "..struct2", ".struct2.", "..", ".", "".
You can use a * to tell scanf to ignore an element:
const char *str = "struct1.struct2.struct3.int";
int main() {
char buf[256];
int i = sscanf(str, "%*[^.].%[^.]", buf);
printf("%d >%s<\n", i, buf);
return 0;
}
This outputs as expected:
1 >struct2<
because exactly 1 element was assigned even if another one was parsed.
Let's say I have the following string stored in char *m;
char *m = "K: someword\r\n";
The m will be inputed by the user so the user will write in the console:
K: someword\r\n
The someword can have different length, while K: \r\n will always be the same.
Now my question is, which is the best way after I read this input to extract someword from it and save it into a new char* variable?
Use sscanf() like this:
#include <stdio.h>
int main (void)
{
char buffer [50], k, return_car, new_line;
int n = sscanf ("K: someword\r\n", "%c: %s%c%c", &k, buffer, &return_car, &new_line);
printf ("The word is \"%s\". sscanf() read %d items.\n", buffer, n);
return 0;
}
Output:
The word is "someword". sscanf() read 4 items
Since both the substrings we aren't interested in ("K: " and "\r\n") are of fixed length, you can do this:
char *s;
size_t len = strlen(m);
s = malloc(len);
strcpy(s, m + 3);
s[len - 4] = 0;
printf("%s\n", s);
free(s);
Note that I declared a new char * variable to copy to since m is in read-only memory, and that robust code would handle the case where malloc failed and returned NULL.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char *m = "K: someword\r\n";
const size_t someword_len = strlen(&m[3]);
char *someword = malloc(someword_len);
if (someword == NULL) { fprintf(stderr, "Malloc error\n"); abort(); }
memcpy(someword, &m[3], someword_len - 2);
someword[someword_len - 1] = '\0';
puts(someword);
free(someword);
}
You assume that string m always starts with "K: " (that's 3 characters) and ends with "\r\n" (that's two characters).
I believe strlen(m) will be faster then strchr(m, '\r') or strrchr(m, '\r') on most platforms
After you have the length of the string, using memcpy instead of strcpy will be faster.
Remember to null terminate your string
Remember to handle errors.
Ok, so I'm going to explain my program.
It takes a text file that's setup as such: in pairs, first line being the title of an experiment, and the second line being 10 numbers separated by spaces. It saves the first lines of pairs in *experiments and the second lines of pairs in data. The last line is *** END *** which is what it's supposed to end with.
For some reason *** END *** doesn't end the program. Any ways I can fix this? I'm assuming it's because fgets gives str blank spaces (99 chars total) so that the string in quotes will never be equal to str?
Thanks.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int var;
int i=0,j,k;
char seps[] = " ";
char *experiments[20];
int data[10][20];
char str[100]; // make sure that this size is enough to hold the single line
char *ptr, *token;
int no_line=1;
while(fgets(str,100,stdin) != NULL && strcmp(str,"*** END ***"))
{
if(no_line % 2 == 0)
{
k=0;
token = strtok (str, seps);
while (token != NULL)
{
sscanf (token, "%d", &var);
data[i][k++] = var;
token = strtok (NULL, seps);
}
i++;
/*read integer values from the string "str" using sscanf, sscanf can be called in a loop with %d untill it fails */
}
else
{
ptr = strdup(str);
experiments[i] = ptr;
/*strore string in your variable "experiments" , before copying allocate a memory for the each entry */
}
no_line++;
}
for(j=0;j<i;j++)
{
printf("%s",experiments[j]);
for(k=0;k<10;k++)
{
printf("%d ",data[j][k]);
}
printf("\n");
}
}
You're declaring i here ...
int i,j,k;
... and using it here ...
data[i][k++] = var;
Nowhere do you initialize i. Also, why does data need to be a 2D array? Can't it just be a 1D array?
int data[10];
...
data[k++] = var;
From this code, int i seems to be declared, but not initialized?
data[i][k++] = var;
It may be helpful to use Eclipse or Code Block IDE to try small testable codes because it has all sorts of syntax and error checking features.
I'm new to C language and I need a help on String functions.
I have a string variable called mcname upon which I would like to compare the characters between special characters.
For example:
*mcname="G2-99-77"
I expect the output to be 99 as this is between the - characters.
How can I do this in C please?
Travel the string (walking pointer) till u hit a special character.
Then start copying the characters into seperate array untill u hit the next special character (Place a null character when u encounter the special character second time)
You can do this by using strtok or sscanf
using sscanf:
#include <stdio.h>
int main()
{
char str[64];
int out;
char mcname[] = "G2-99-77";
sscanf(mcname, "%[^-]-%d", str, &out);
printf("%d\n", out);
return 0;
}
Using strtok:
#include <stdio.h>
#include <string.h>
int main()
{
char *str;
int out;
char mcname[] = "G2-99-77";
str = strtok(mcname, "-");
str = strtok (NULL, "-");
out = atoi(str);
printf("%d\n", out);
return 0;
}
sscanf() has great flexibility. Used correctly, code may readily parse a string.
Be sure to test the sscanf() return value.
%2[A-Z0-9] means to scan up to 2 characters from the set 'A' to 'Z' and '0' to '9'.
Use %2[^-] if code goal is any 2 char other than '-'.
char *mcname = "G2-99-77";
char prefix[3];
char middle[3];
char suffix[3];
int cnt = sscanf(mcname, "%2[A-Z0-9]-%2[A-Z0-9]-%2[A-Z0-9]", prefix, middle,
suffix);
if (cnt != 3) {
puts("Parse Error\n");
}
else {
printf("Prefix:<%s> Middle:<%s> Suffix:<%s>\n", prefix, middle, suffix);
}