Re: reading in multiple strings with scanf



On Dec 3, 7:13 am, Heiko Schepanski <deutron...@xxxxxx> wrote:
nick_keighley_nos...@xxxxxxxxxxx wrote:
On 3 Dec, 12:23, Heiko Schepanski <deutron...@xxxxxx> wrote:

No matter what I input into the console, scanf returns 1 but it should
be able to read all 6 fields in correctly. What am I doing wrong?

please give an example of your input

struct _bauelement
{
        char kennnummer[9+1];
        char bezeichnung[30+1];
        char einheit[10+1];
        double wert;
        char toleranzklasse;
        char bemerkungen[120+1];

} be;

int num = scanf("%s, %s, %s, %lf, %c, %s",
        be.kennnummer, sizeof(be.kennnummer),
        be.bezeichnung, sizeof(be.bezeichnung),
        be.einheit, sizeof(be.einheit),
        &be.wert,
        &be.toleranzklasse,
        be.bemerkungen, sizeof(be.bemerkungen));

in addition to viza's comments scanf() doesn't accept the sizeof
arguments you have in your call. If it read a second string it
would try to store it in sizeof(be.kennnummer) which I'd expect
to give a segmentation error. Re-read your documentation for scanf().

I suspect you need to use fgets() the parse the string "by hand".
Consider strtok().

--
Nick Keighley

 Testing can show the presense of bugs, but not their absence.
                -- Dijkstra

It's me again :-)

Since I have multiple times in my app a call to printf, sprintf, scanf,
and fscanf with always the same arguments (see my other posts) I came up
with an absolutely sick idea. Because I need *all* values from my struct
and I use it in the same order they appear in the struct I tried:

printf("%9s, %30s, %10s, %.2lf, %i, %s\n", be); // be is the struct var

Sadly to say, it didn't work and threw an exception :-(

Maybe something like this:

#include <string.h>
#include <limits.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>

char *getsafe(char *buffer, int count)
{
char *result = buffer,
*np;
if ((buffer == NULL) || (count < 1))
result = NULL;
else if (count == 1)
*result = '\0';
else if ((result = fgets(buffer, count, stdin)) != NULL)
if (np = strchr(buffer, '\n'))
*np = '\0';
return result;
}

/* The default delimiters are chosen as some ordinary white space
characters: */
static const char default_delimiters[] =
{' ', '\n', '\t', '\r', '\f', 0};

/*
* The tokenize() function is similar to a reentrant version of strtok
().
* It parses tokens from 's', where tokens are substrings separated by
* characters from 'delimiter_list'.
* To get the first token from 's', tokenize() is called with 's' as
its first
* parameter.
* Remaining tokens from 's' are obtained by calling tokenize() with
NULL for
* the first parameter.
* The s of delimiters, identified by 'delimiter_list', can change
from call
* to call.
* If the list of delimiters is NULL, then the standard list
'default_delimiters'
* (see above) is used.
* tokenize() modifies the memory pointed to by 's', because it writes
null
* characters into the buffer.
*/
char *tokenize(char *s, const char *delimiter_list, char
**placeholder)
{
if (delimiter_list == NULL)
delimiter_list = default_delimiters;

if (delimiter_list[0] == 0)
delimiter_list = default_delimiters;

if (s == NULL)
s = *placeholder;

if (s == NULL)
return NULL;
/*
* The strspn() function computes the length of the initial segment of
the first
* string that consists entirely of characters contained in the second
string.
*/
s += strspn(s, delimiter_list);
if (!s[0]) {
*placeholder = s;
return NULL;
} else {
char *token;
token = s;
/*
* The strpbrk() function finds the first occurrence of any character
contained in
* the second string found in the first string.
*/
s = strpbrk(token, delimiter_list);
if (s == NULL)
*placeholder = token + strlen(token);
else {
*s++ = 0;
*placeholder = s;
}
return token;
}
}

#ifdef UNIT_TEST

static char whitespace[UCHAR_MAX + 1];

/*
This test will create token separators as any whitespace or any
punctuation
marks:
*/
void init_whitespace()
{
int i;
int index = 0;
for (i = 0; i < UCHAR_MAX; i++) {
if (isspace(i)) {
whitespace[index++] = (char) i;
}
if (ispunct(i)) {
whitespace[index++] = (char) i;
}
}
}

static struct bauelement {
char kennnummer[9 + 1];
char bezeichnung[30 + 1];
char einheit[10 + 1];
double wert;
char toleranzklasse;
char bemerkungen[120 + 1];
} be;

char *strstart(char *s)
{
while (isspace(*s))
s++;
return s;
}

void get_be(char *ts, char *white, struct bauelement * be)
{
char *p = NULL;
char *token;
int iteration = 0;
token = tokenize(ts, white, &p);
while (token) {
switch (iteration++) {
case 0:
strncpy(be->kennnummer, strstart(token), sizeof be-
kennnummer);
break;
case 1:
strncpy(be->bezeichnung, strstart(token), sizeof be-
bezeichnung);
break;
case 2:
strncpy(be->einheit, strstart(token), sizeof be->einheit);
break;
case 3:
be->wert = atof(strstart(token));
break;
case 4:
be->toleranzklasse = *strstart(token);
break;
case 5:
strncpy(be->bemerkungen, strstart(token), sizeof be-
bemerkungen);
break;
}
token = tokenize(NULL, white, &p);
}
}

static char str[256] = "1234, Plate, cm, 14.99, 60, Part is OK";

int main(void)
{
char yourstring[256];
char ws[2] = ",";
get_be(str, ws, &be);
printf("%s, %s, %s, %g, %d, %s.\n", be.kennnummer, be.bezeichnung,
be.einheit, be.wert, be.toleranzklasse, be.bemerkungen);
puts("You give me one:");
fflush(stdout);
getsafe(yourstring, sizeof yourstring);
get_be(yourstring, ws, &be);
printf("%s, %s, %s, %g, %d, %s.\n", be.kennnummer, be.bezeichnung,
be.einheit, be.wert, be.toleranzklasse, be.bemerkungen);

return 0;
}
/* Some possible output:
1234, Plate, cm, 14.99, 54, Part is OK.
You give me one:
1212, Silverware, inches, 12, 32, What is not
1212, Silverware, inches, 12, 51, What is not.
*/
#endif
.



Relevant Pages

  • Re: parsing VB code with a regex
    ... Any characters to the right of the comment are ... So, now that we're down to a single string, and a few simple rules: ... All other tokens should be matched. ... regular expression, it is not available for further matching. ...
    (microsoft.public.dotnet.general)
  • Re: Base36
    ... that you've made is a string being attached. ... > "Justin Rogers" wrote in message ... >>> characters that may be confused for other characters when read by a> human. ... >>>> conversion is each direction is based on the tokens and powers arrays. ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: reading in multiple strings with scanf
    ... in addition to viza's comments scanfdoesn't accept the sizeof ... I suspect you need to use fgetsthe parse the string "by hand". ... It parses tokens from 's', where tokens are substrings separated by ... characters from 'delimiter_list'. ...
    (comp.lang.c)
  • Re: Japanese strings get mangled when sent from VB6 to VC++ dll
    ... In the second string, the first three characters are wrong. ... The first character comes up a rectangle, ...
    (microsoft.public.vb.general.discussion)
  • Re: frustrated by fscanf and sscanf
    ... It parses tokens from 'string', ... separated by characters from 'delimiter_list'. ... /* This test will create token separators as any whitespace or any ...
    (comp.lang.c)