using char* as arg to scanf (in function), need help 
Author Message
 using char* as arg to scanf (in function), need help

Hi people,

Got a problem with scanf. The code is below. The problem exactly is
such:

As I understand, pointer is the variable, which hold address of other
object as a value. Because of it, one can call scanf without & in
string args.

Imagine, that &a[0] is 0xbffffdd4. When I call scanf("%s", a), it uses
0xbfffdd4 as address (the value of a). Is everything correct beyond
this point ?

OK. Now I call read_store_binary(a); a is a char*, so it is going into
function by value.  It's ok, 'cause the value of the pointer is the
address it is _pointing to_. So, in call to read_store_binary(a),
formal argument s becomes s == 0xbffffdd4 (Confirmed by GDB); So, as I
understand it is pointing to _the same_ memory location as a in
main(). Of course the address of s itself (&s) will be different from
a. Everything okay beyond this point ?

Let's continue. The dragon is in call to scanf() in
read_store_binary(). After that call, the s pointer points somewhere
to 0xbffffd90, and scanf() return "non 1".

I looked through the C faq and did some googling, but it seems i can't
figure out why scanf() behaviour is such. Please help me.

I use Redhat 5.2
x86 linux 2.0.36
gcc version 2.7.2.3
glibc version 2.0.7-29

<-- Cut here -->
#include <stdio.h>
#include <stdlib.h>
#define INTBITS 8 * sizeof(int)
void read_store_bin(char *s);

int main(void)
{
        char a[ INTBITS + 1];
        char b[ INTBITS + 1];

        printf("a: %p\n", a);
        printf("&a: %p\n", &a);
        printf("&a[0]: %p\n", &a[0]);

        read_store_bin(a);
        read_store_bin(b);

        /* processing ... */

        return 0;

Quote:
}

void read_store_bin(char *s)
{
        char fmt[7];

        sprintf(fmt, "%%%d[01]", INTBITS);
        printf("Input binary value(up to %d bits).\n", INTBITS);
        if (scanf(fmt, s) != 1) {       /* DRAGON HERE ! */
                fprintf(stderr,"Non-binary value.\n");
                exit(1);
        }

Quote:
}

<-- eof -->
Thanks,
Oleg Frolov



Sun, 12 Jun 2005 20:51:31 GMT  
 using char* as arg to scanf (in function), need help

Quote:
> Got a problem with scanf. The code is below. The problem exactly is
> such:

> As I understand, pointer is the variable, which hold address of other
> object as a value. Because of it, one can call scanf without & in
> string args.

Mmmm... not exactly. scanf() will retreive (and sometime convert) data from
stdin, and store it to user's variables which addresses have been passed to
scanf as formal parameters.

   int x;
   char s[123];

   scanf ("%d %s, &x, s);

As you can see the important thing is not the '&', but the fact that an
address is passed, conforming to the format string:

"%d" -> (int *)
"%s" -> (char *)

In that case, and according to the definitions given by the standard, 's' is
a short form for 's + 0' or '&(*(s + 0))' or '&s[0]'.

Quote:
> Imagine, that &a[0] is 0xbffffdd4. When I call scanf("%s", a), it uses
> 0xbfffdd4 as address (the value of a). Is everything correct beyond
> this point ?

In the main lines, yes.

Quote:
> OK. Now I call read_store_binary(a); a is a char*, so it is going into
> function by value.  It's ok, 'cause the value of the pointer is the
> address it is _pointing to_. So, in call to read_store_binary(a),
> formal argument s becomes s == 0xbffffdd4 (Confirmed by GDB); So, as I
> understand it is pointing to _the same_ memory location as a in
> main(). Of course the address of s itself (&s) will be different from
> a. Everything okay beyond this point ?

Fine.

Quote:
> Let's continue. The dragon is in call to scanf() in
> read_store_binary(). After that call, the s pointer points somewhere
> to 0xbffffd90, and scanf() return "non 1".

It means that the conversion failed.

Quote:
> I looked through the C faq and did some googling, but it seems i can't
> figure out why scanf() behaviour is such. Please help me.

> <-- Cut here -->
> #include <stdio.h>
> #include <stdlib.h>
> #define INTBITS 8 * sizeof(int)

Macros are tricky. Should be:

#define INTBITS (8 * sizeof(int))
or
#define INTBITS (CHAR_BIT * sizeof(int))

(not fully portable, but it's not the point)

Quote:
> void read_store_bin(char *s);

> int main(void)
> {
>      char a[ INTBITS + 1];
>      char b[ INTBITS + 1];

>      printf("a: %p\n", a);

Be awared that "%p" wants a (void*):

      printf("a: %p\n", (void*) a);

Quote:
>      printf("&a: %p\n", &a);
>      printf("&a[0]: %p\n", &a[0]);

Once fixed, they all should display the same value.

Quote:
>      read_store_bin(a);
>      read_store_bin(b);

>      /* processing ... */

>      return 0;
> }

> void read_store_bin(char *s)

could be

void read_store_bin (char const *s)

Quote:
> {
>      char fmt[7];

>      sprintf(fmt, "%%%d[01]", INTBITS);

for example, this expands to

       "%16[01]"

sounds weird... What do you want exactly?

Quote:
>      printf("Input binary value(up to %d bits).\n", INTBITS);
>      if (scanf(fmt, s) != 1) {     /* DRAGON HERE ! */

Of course: a bad scanf() format invokes undefined behaviour.

Quote:
>           fprintf(stderr,"Non-binary value.\n");
>           exit(1);
>      }
> }

--
-ed- emdel at noos.fr ~]=[o
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/
C-library: http://www.dinkumware.com/manuals/reader.aspx
"Mal nommer les choses c'est ajouter du malheur au monde."
-- Albert Camus.


Sun, 12 Jun 2005 22:13:43 GMT  
 using char* as arg to scanf (in function), need help

Quote:


> for example, this expands to

>        "%16[01]"

> sounds weird... What do you want exactly?

I wanted to limit digit count in input to number of bits in int. On my
machine, for example, it expands to "%32..."

Quote:
> >      if (scanf(fmt, s) != 1) {     /* DRAGON HERE ! */

> Of course: a bad scanf() format invokes undefined behaviour.

Thanks, fixed it already. Forgot to allocate place for '\0'.
How lame of me...


Sat, 18 Jun 2005 22:28:15 GMT  
 using char* as arg to scanf (in function), need help

...
Quote:
> As I understand, pointer is the variable, which hold address of other
> object as a value. Because of it, one can call scanf without & in
> string args.

A pointer *value* is the address of an(other) object, and a pointer
*variable* can store such a value, yes.  You can usually pass a
string to scanf, or any other function, without an &, because
normally you use a char array which automatically "decays"
(converts) to a pointer to char which is what you want.  In fact,
it is technically wrong to pass & of a char array where a char*
is required, although it almost always works.  FAQ 6.12.

What pointer variables (or parameters) do enable is passing
different addresses, incuding different arrays, at different times;
or passing the address of a scalar without using & in the call,
but only if it was previously taken with & and stored.

Quote:
> Imagine, that &a[0] is 0xbffffdd4. When I call scanf("%s", a), it uses
> 0xbfffdd4 as address (the value of a). Is everything correct beyond
> this point ?

> OK. Now I call read_store_binary(a); a is a char*, so it is going into
> function by value.  It's ok, 'cause the value of the pointer is the
> address it is _pointing to_. So, in call to read_store_binary(a),
> formal argument s becomes s == 0xbffffdd4 (Confirmed by GDB); So, as I
> understand it is pointing to _the same_ memory location as a in
> main(). Of course the address of s itself (&s) will be different from
> a. Everything okay beyond this point ?

Correct "to" (not "beyond") these points, yes.  (The specific
address is implementation dependent, but the principles are
correct everywhere.)

Quote:
> Let's continue. The dragon is in call to scanf() in
> read_store_binary(). After that call, the s pointer points somewhere
> to 0xbffffd90, and scanf() return "non 1".

Not on my system.  The call to scanf in the FIRST call
to read_store_binary succeeds, returns 1, and it returns
to main() (note that high-level gdb does not stop in between
because you do not have an explicit return statement).

It is the SECOND call to read_store_binary, with argument b,
where the scanf() fails, reaching the printf("Non-binary value"),
and now the value of s is &b[0], which is different from &a[0].
This second scanf fails because the \n left after the first value
was entered and parsed does not match %[01], and %[ and
%c unlike other scanf specifiers do not skip whitespace.
FAQ 12.18.  If I enter 2*INTBITS contiguously on the first
input line, BEFORE the second prompt, it "works".

Aside: we don't call problems or errors "dragons" in English.
But it was obvious enough what you intended.

...

Quote:
> #define INTBITS 8 * sizeof(int)
...
> printf("a: %p\n", a);
> printf("&a: %p\n", &a);
> printf("&a[0]: %p\n", &a[0]);

Technically %p requires an argument of type void*,
not any other pointer type, so you should cast these.
In practice it usually works.  In fact in practice treating
any pointer as a number, with %u or %lu etc., usually
works, but you should try not to rely on it.

...

Quote:
> sprintf(fmt, "%%%d[01]", INTBITS);
> printf("Input binary value(up to %d bits).\n", INTBITS);

INTBITS has type size_t, which is definitely not signed int,
and not necessarily even unsigned int.  You should either
cast it, or in C99 only use %zu.

--
- David.Thompson 1 now at worldnet.att.net



Mon, 20 Jun 2005 06:32:40 GMT  
 using char* as arg to scanf (in function), need help


Wed, 18 Jun 1902 08:00:00 GMT  
 using char* as arg to scanf (in function), need help
Hi people,

I applied all (i hope) recomendations to my source. Here is final
version. And it's working for me. Any suggestions? Comments?

I really tried hard.

Thanks,
Oleg

<-- Cut here -->
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

/* macros are tricky :) CHAR_BIT is more portable, than '8' */
#define INTBITS (CHAR_BIT * sizeof(int))

void read_store_bin(char *s);

int main(void)
{
        char a[ INTBITS + 1];
        char b[ INTBITS + 1];

        /* Pointer of type pointer-to-T (array first element), FAQ 6.12*/
        printf("a: %p\n", (void*) a);

/* Pointer-to-array-of-T (entire array), FAQ 6.12*/
        printf("&a: %p\n", (void*) &a);      

        /* Ponter of type pointer-to-T (first element) ?? */
        printf("&a[0]: %p\n", &a[0]);

        read_store_bin(a);
        read_store_bin(b);

        /* processing ... */

        return 0;

Quote:
}

void read_store_bin(char *s)
{
        /* 1 for '%', 2 for bit count, + 2 for '%[' + 3 for '01]' + 1 for
'\0'*/
        char fmt[9];

        /* Limit input to characters 0 and 1. Maximal character count is
        number of bits in int on _that_ machine */
        sprintf(fmt, "%%%u[01]", (unsigned)INTBITS);

        printf("Input binary value(up to %u bits).\n", (unsigned) INTBITS);

        /* problem were here (due to lack of '\0' in format string)!
         it went away now, though :)*/

        if (scanf(fmt, s) != 1) {                      
                fprintf(stderr,"Non-binary value.\n");
                exit(1);
        }
        /* if got so far,  kill line */
        while (getchar() != '\n') ;

Quote:
}

<-- eof -->


Wed, 22 Jun 2005 17:42:56 GMT  
 using char* as arg to scanf (in function), need help

Quote:
> Hi people,

> I applied all (i hope) recomendations to my source. Here is final
> version. And it's working for me. Any suggestions? Comments?

> I really tried hard.

My tries (on the same machine, i386/Windows)

<Borland C memory 'SMALL'>

a: FFE4
&a: FFE4
&a[0]: FFE4
Input binary value(up to 16 bits).
0101
Input binary value(up to 16 bits).
012

(sounds that the scanf() with the '[01]' thing is broken. I don't use
scanf(). Too tricky for me).

<Borland C memory 'LARGE'>

a: 8FEC:0FEE
&a: 8FEC:0FEE
&a[0]: 8FEC:0FEE
Input binary value(up to 16 bits).
0101
Input binary value(up to 16 bits).
012

<DJGPP>

a: 0253FDF8
&a: 0253FDF8
&a[0]: 0253FDF8
Input binary value(up to 32 bits).
0101
Input binary value(up to 32 bits).
012

As you can see, portability issues is not just a mind game. It's a reality.

- You can say in advance how will the pointers value be displayed
- The sizeof an int is changing with the implementation (on the same
machine, I insist)

Quote:
> <-- Cut here -->
> #include <stdio.h>
> #include <stdlib.h>
> #include <limits.h>

> /* macros are tricky :) CHAR_BIT is more portable, than '8' */
> #define INTBITS (CHAR_BIT * sizeof(int))

Not portable. There is nothing in the standard that prevents, for example, an
int of 4 bytes to have an effective range of 24 bits.

sizeof (T) returns the number of bytes of an object of type T, not a number
of bits, because some of them could be used for other purposes (trap
representation for example).

The effective range of the plain types in your implementation is defined in
<limits.h>

INT_MIN
INT_MAX
etc.

regardless their width in number of bits.

Quote:
> void read_store_bin(char *s);

Following the 'define before use' design principle avoids to have a separated  
prototype here. In most cases, separated prototypes belong to headers.

Quote:
> int main(void)
> {
>      char a[ INTBITS + 1];
>      char b[ INTBITS + 1];

>      /* Pointer of type pointer-to-T (array first element), FAQ 6.12*/
>      printf("a: %p\n", (void*) a);

> /* Pointer-to-array-of-T (entire array), FAQ 6.12*/
>      printf("&a: %p\n", (void*) &a);    

>      /* Ponter of type pointer-to-T (first element) ?? */

Yes. It is the first element. BTW, AFAIK, this is the canonical definition of
the address of an array.

Quote:
>      printf("&a[0]: %p\n", &a[0]);

      printf("&a[0]: %p\n",  (void *) &a[0]);

Quote:

>      read_store_bin(a);
>      read_store_bin(b);

>      /* processing ... */

>      return 0;
> }

> void read_store_bin(char *s)
> {
>      /* 1 for '%', 2 for bit count, + 2 for '%[' + 3 for '01]' + 1 for
> '\0'*/
>      char fmt[9];

>      /* Limit input to characters 0 and 1. Maximal character count is
>      number of bits in int on _that_ machine */
>      sprintf(fmt, "%%%u[01]", (unsigned)INTBITS);

>      printf("Input binary value(up to %u bits).\n", (unsigned) INTBITS);

>      /* problem were here (due to lack of '\0' in format string)!
>       it went away now, though :)*/

>      if (scanf(fmt, s) != 1) {              
>           fprintf(stderr,"Non-binary value.\n");
>           exit(1);
>      }
>      /* if got so far,  kill line */
>      while (getchar() != '\n') ;
> }

I won't say a word about scanf(). I personnaly use fgets(), check the string
manually, and eventually use the appopriate conversion function (strtoul()
can work in base 2 to 36).

--
-ed- emdel at noos.fr ~]=[o
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/
C-library: http://www.dinkumware.com/manuals/reader.aspx
"Mal nommer les choses c'est ajouter du malheur au monde."
-- Albert Camus.



Wed, 22 Jun 2005 20:01:05 GMT  
 using char* as arg to scanf (in function), need help

Quote:


> > I applied all (i hope) recomendations to my source. Here is final
> > version. And it's working for me. Any suggestions? Comments?

> > I really tried hard.

>  My tries (on the same machine, i386/Windows)

>  <Borland C memory 'SMALL'>

>  a: FFE4
>  &a: FFE4
>  &a[0]: FFE4
>  Input binary value(up to 16 bits).
>  0101
>  Input binary value(up to 16 bits).
>  012

>  (sounds that the scanf() with the '[01]' thing is broken. I don't use
>  scanf(). Too tricky for me).

What's tricky? The call scanf("%16[01]", buf) will match a string of up
to 16 '0' or '1' characters. That the program doesn't complain about
"012" is not scanf's fault; scanf converts the "01" and leaves '2' in
stdin. The program subsequently ignores this, but scanf is not to blame
for that.
Try the program again, entering "012" at the first prompt, or some
non-binary string at either.

Gergo
--
Q:      Are we not men?
A:      We are Vaxen.



Thu, 23 Jun 2005 00:09:23 GMT  
 using char* as arg to scanf (in function), need help

Quote:


> > I applied all (i hope) recomendations to my source. Here is final
> > version. And it's working for me. Any suggestions? Comments?

> > I really tried hard.

>  My tries (on the same machine, i386/Windows)

>  <Borland C memory 'SMALL'>

>  a: FFE4
>  &a: FFE4
>  &a[0]: FFE4
>  Input binary value(up to 16 bits).
>  0101
>  Input binary value(up to 16 bits).
>  012

>  (sounds that the scanf() with the '[01]' thing is broken. I don't use
>  scanf(). Too tricky for me).

What's tricky? The call scanf("%16[01]", buf) will match a string of up
to 16 '0' or '1' characters. That the program doesn't complain about
"012" is not scanf's fault; scanf converts the "01" and leaves '2' in
stdin. The program subsequently ignores this, but scanf is not to blame
for that.
Try the program again, entering some string that does not start with
binary digits.

Gergo
--
Q:      Are we not men?
A:      We are Vaxen.



Thu, 23 Jun 2005 00:11:13 GMT  
 using char* as arg to scanf (in function), need help

Quote:
> What's tricky? The call scanf("%16[01]", buf) will match a string of up
> to 16 '0' or '1' characters. That the program doesn't complain about
> "012" is not scanf's fault; scanf converts the "01" and leaves '2' in
> stdin. The program subsequently ignores this, but scanf is not to blame
> for that.
> Try the program again, entering some string that does not start with
> binary digits.

I understand, but there is no way to know that there was an error in the
typing like "012" or "100111O1". Scary...

--
-ed- emdel at noos.fr ~]=[o
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/
C-library: http://www.dinkumware.com/manuals/reader.aspx
"Mal nommer les choses c'est ajouter du malheur au monde."
-- Albert Camus.



Thu, 23 Jun 2005 00:55:06 GMT  
 using char* as arg to scanf (in function), need help
Quote:


> > What's tricky? The call scanf("%16[01]", buf) will match a string of up
> > to 16 '0' or '1' characters. That the program doesn't complain about
> > "012" is not scanf's fault; scanf converts the "01" and leaves '2' in
> > stdin. The program subsequently ignores this, but scanf is not to blame
> > for that.
> > Try the program again, entering some string that does not start with
> > binary digits.

> I understand, but there is no way to know that there was an error in the
> typing like "012" or "100111O1". Scary...

I also use fgets() + manual parsing tehnique and think it is more
robust for more complicated cases. But in my "toy" program it would be
unnecessaty bloat (I think). Remember, it's just small program. :)

Oleg



Thu, 23 Jun 2005 18:48:58 GMT  
 
 [ 11 post ] 

 Relevant Pages 

1. Need help with scanf function / homework assignment - cs120p6x.c (0/1)

2. Need help with scanf function / homework assignment - cs120p6x.c (1/1)

3. Using unsigned char in (char *) functions...

4. HELP - Scanf conversion 4 unsigned char

5. Examples needed for understanding,scanf function, specifiers %[],%[^],%p,%n

6. Troubles using C's scanf Function

7. need help using regexp() function

8. Need help on using function GetDriveType.

9. I need help for scanf()

10. : need some help with scanf().

11. Need SCANF help

12. I need some help re: scanf, getchar

 

 
Powered by phpBB® Forum Software