2

In the following code i need to extract doubles and string from a line formated like this "[double,double] string" with the string starting as a first non white character and any number of white characters after [

I do care about loading properly the numbers, but don't care about the string (could even be empty).

char *read; size_t len=0; double x,y; int size; getline(&read,&len,stdin); char *name=(char*)malloc(strlen(read)); if(sscanf(read,"[ %lf, %lf ] %n",&x,&y,&size)!=2) { return 0; } sscanf(read,"%*.c%[^\n]s",size,name); 

I already have implemented everything. I know that the second sscanf cannot work like this, only there to represent my thought. Is there any way how to get the size variable to be a parameter of how many characters not to load? I searched everything and the only thing i could find was to have number defined, which does not help here.

Also I am quite new to programming, so please be considerate about me not knowing maybe basic stuff.

9
  • You can use sprintf to build the format string for sscanf. Commented Nov 19, 2019 at 20:31
  • Is the getline you use something you wrote yourself? Edit: Found it, POSIX.1-2008 Commented Nov 19, 2019 at 20:32
  • 1
    Seems like all C to me. Commented Nov 19, 2019 at 20:35
  • I use it to automatically dynamically allocate the "read" pointer array. I got a bit of help implementing it. Commented Nov 19, 2019 at 20:35
  • @VincentJakl -- I am sure C++ has all of the facilities without any manual memory management or hard-to-decipher sscanf calls. Commented Nov 19, 2019 at 20:35

2 Answers 2

3

If I understand your question and you want to separate, e.g. "[123.456, 789.34] Daffy Duck" into the two doubles and the name using getline and sscanf allocating storage for name, then a single call to POSIX getline() and a single call to sscanf reading name into a temporary array and then allocating and copying to name will allow you to size name exactly as required.

For example:

#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXN 1024 int main (void) { double x, y; char *read = NULL, *name = NULL, tmp[MAXN]; size_t n = 0; fputs ("input: ", stdout); if (getline (&read, &n, stdin) == -1) { fputs ("error: getline.\n", stderr); return 1; } if (sscanf (read, " [%lf ,%lf ] %1023[^\n]", &x, &y, tmp) == 3) { size_t len = strlen (tmp); if (!(name = malloc (len + 1))) { perror ("malloc-name"); return 1; } memcpy (name, tmp, len + 1); printf ("x : %f\ny : %f\nname: %s\n", x, y, name); free (name); } free (read); } 

There is no need to cast the return of malloc, it is unnecessary. See: Do I cast the result of malloc?

Also note that when the parameter n = 0 as above, getline() will allocate storage as needed to handle your input line. So following the call to getline(), read has allocated storage duration. You will need to free read to avoid leaking memory and you cannot simply return a pointer to the beginning of name within read as you must preserve a pointer to the beginning of read in order to be able to free it.

Example Use/Output

Then by including appropriate whitespace in your sscanf format-string you can flexibly read your input regardless of leading or intervening whitespace, e.g.

$ ./bin/readxyname input: [123.456, 789.34] Daffy Duck x : 123.456000 y : 789.340000 name: Daffy Duck 

With no whitespace in input:

$ ./bin/readxyname input: [123.456,789.34]Daffy Duck x : 123.456000 y : 789.340000 name: Daffy Duck 

With arbitrary whitespace in input:

$ input: [ 123.456 , 789.34 ] Daffy Duck x : 123.456000 y : 789.340000 name: Daffy Duck 

Look things over and let me know if you have further questions.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you, this is what I needed.
Glad it helped :) Know there are many many ways to do this. The use of sscanf here is probably one of the easier ones. So long as you understand that carefully including whitespace in your format-string allows sscanf to ignore the whitespace -- which allows you a really flexible way to handle this set of doubles and a name. Good luck with your coding.
0

scanf may ignore matches with the * formatter. More on that on conversion specifications here. That way, you can match and store double and match and ignore the following string i.e. %*s.

A bit easier way could be searching for ] with i.e. strchr and then passing sscanf only the string portion you're actually interested in (now that you know where it begins and ends) through simple pointer arithmetics.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.