LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   C scanf arbitrarily deletes contents of another variable??? (https://www.linuxquestions.org/questions/programming-9/c-scanf-arbitrarily-deletes-contents-of-another-variable-759511/)

phenyloxime 10-03-2009 10:09 PM

C scanf arbitrarily deletes contents of another variable???
 
Ok, I am in the process of writing a program that plays the game mancala. I wanted to create a function that requires the player to choose a number between one and six, should be simple right? I kept having problems, so I started testing stuff out. This chunk of code is giving me a real headache:
Code:

#include <stdio.h>
#include <stdlib.h>



short move();


int main()
{
  short q = move();
  printf("%d is a great choice!!!\n", q);
  return 0;
}

short move()
{
  short M;
  short i;
  i = 1;
  printf("pre loop, i is: %d\n", i);    /*value of i just prior to entering the loop */
 
  while (i)
  {
    i = 1;
    printf("Please Select a Bowl to move (1 - 6)\n"); 
    printf("pre scan, i is: %d\n", i); /*value of i just before scanf statement*/
    scanf("%d",&M);
    printf("post scan, i is: %d\n", i); /*and just after */
  }

  return M;
}

And here is the Output I get:
Code:

adam@tiamat:~/Mancala$ gcc scanf_test.c
adam@tiamat:~/Mancala$ ./a.out
pre loop, i is: 1
Please Select a Bowl to move (1 - 6)
pre scan, i is: 1
4
post scan, i is: 0 <<<-----Here is the problem!!!!! 
4 is a great choice!!!

I am really confused here. Is it my imagination? or is the value of i being arbitrarily set to zero by the scanf function.

I am using gcc version 4.3.2 (Debian 4.3.2-1.1). On a whim, I tried something else out; when I change the 'short' variables to 'int' , the problem seems to dissapear.... I tried changing the format string in the scanf statement from "%d" to "%u" which is listed as the appropriate string for the 'short' type, still no luck. Any insight is gratefully appreciated.

smeezekitty 10-03-2009 10:17 PM

M is not big enough so you are overwriting memory erasing i
try changing short M to long M

lutusp 10-03-2009 10:24 PM

Quote:

Originally Posted by phenyloxime (Post 3706707)
Ok, I am in the process of writing a program that plays the game mancala. I wanted to create a function that requires the player to choose a number between one and six, should be simple right? I kept having problems, so I started testing stuff out. This chunk of code is giving me a real headache:
Code:

#include <stdio.h>
#include <stdlib.h>



short move();


int main()
{
  short q = move();
  printf("%d is a great choice!!!\n", q);
  return 0;
}

short move()
{
  short M;
  short i;
  i = 1;
  printf("pre loop, i is: %d\n", i);    /*value of i just prior to entering the loop */
 
  while (i)
  {
    i = 1;
    printf("Please Select a Bowl to move (1 - 6)\n"); 
    printf("pre scan, i is: %d\n", i); /*value of i just before scanf statement*/
    scanf("%d",&M);
    printf("post scan, i is: %d\n", i); /*and just after */
  }

  return M;
}

And here is the Output I get:
Code:

adam@tiamat:~/Mancala$ gcc scanf_test.c
adam@tiamat:~/Mancala$ ./a.out
pre loop, i is: 1
Please Select a Bowl to move (1 - 6)
pre scan, i is: 1
4
post scan, i is: 0 <<<-----Here is the problem!!!!! 
4 is a great choice!!!

I am really confused here. Is it my imagination? or is the value of i being arbitrarily set to zero by the scanf function.
I am using gcc version 4.3.2 (Debian 4.3.2-1.1). Any insight is gratefully appreciated. On a whim, I tried something else out; when I change of the the 'short' variables to 'int' , the problem seems to dissapear....

I was ready to post when I saw you scanning for an int with a short target. Then I saw you came to the same conclusion. Shorts aren't ints (sometimes they are, but it's the principle) and you'll get into trouble using functions like scanf, because they can't validate their target.

You know, you might be under some obligation to use C-era functions, but C++ has much more robust methods to deal with these issues -- methods that don't get confused like this, and that are easier to understand as well.

smeezekitty 10-03-2009 10:24 PM

Quote:

Originally Posted by phenyloxime (Post 3706707)
On a whim, I tried something else out; when I change of the the 'short' variables to 'int' , the problem seems to dissapear....

you solved your own problem

Wim Sturkenboom 10-05-2009 06:33 AM

%u indicates unsigned, not short. Try %hd

And use gcc -Wall as it would warn you
Code:

wim@btd-techweb01:~/progs/lq$ gcc -Wall main.c -o mytest
main.c: In function `move':
main.c:28: warning: int format, different type arg (arg 2)
wim@btd-techweb01:~/progs/lq$


phenyloxime 10-05-2009 09:12 AM

Thank you guys! So lets say I declare three variables; int X int Y and int Z inside some function. I am telling the compiler to allocate three blocks of memory that are the size of 'int' four bytes I think? and these are located immediately one after the other? I haven't had a chance yet to test stuff out. I am basically doing the 'teach yourself C ' thing, C++ with all of its classes and member functions seems both incredibly powerful but extremely intimidating!!! The -Wall flag stands for 'all warnings' or something similar? Thanks guys for all of your insight on this.

johnsfine 10-05-2009 09:23 AM

Quote:

Originally Posted by phenyloxime (Post 3708343)
I declare three variables; int X int Y and int Z inside some function. I am telling the compiler to allocate three blocks of memory that are the size of 'int' four bytes I think?

Correct.

Quote:

and these are located immediately one after the other?
Maybe.

If you compile without optimization, the compiler is likely to place them that way. If you use all their addresses (as with scanf) then even with optimization, the compiler might place them that way.

But there is no rule about that, so don't try to depend on the placement.

phenyloxime 10-05-2009 10:10 PM

I think I have encountered precisely what johnsfine just said. When I add a printf line, to look at the address of each variable, The problem dissappears:
Code:

short move()
{
  short M;
  short i;
  i = 1;
  /*printf("Address of M: %p, Address of i: %p,\n",&M,&i);*/   
  printf("pre loop, i is: %d\n", i);
 
  while (i)
  {
    i = 1;
    printf("Please Select a Bowl to move (1 - 6)\n");
    printf("pre scan, i is: %d\n", i);
    scanf("%u",&M);
    printf("post scan, i is: %d\n", i);
    printf("Address of M: %p, Address of i: %p,\n",&M,&i);
  }

When I comment out both print-lines, it breaks again... this is truly fascinating!!!

Incidentally, the addresses of each variable look like they are adjacent to each other
Code:

Address of M: 0xbfabcee6, Address of i: 0xbfabcee4
How would I find out the addressing of these variables without printing them? Are the actual addresses of variables located somewhere in the compiled binary?

smeezekitty 10-05-2009 10:20 PM

JUST USE INT INSTEAD OF SHORT.
why not?

Wim Sturkenboom 10-06-2009 05:02 AM

You don't want to care about that; that's what high level languages are for. Just use the proper types or the %hd as per my previous post. I you want to care about those things, use assembly ;)

The only time that you need to be aware of it is if you want to dump data from e.g. a file or serial port into a struct.

jiml8 10-06-2009 05:32 AM

Quote:

I you want to care about those things, use assembly
Or use C.

To find the address of any variable X, take &X, which explicitly means "return the address of X". This is the core mechanism of pointers, which are very important in both C and C++.

In the context of your game, you shouldn't need a lot of this, but in almost all circumstances you can make your program more efficient by using pointers.

johnsfine 10-06-2009 08:12 AM

Quote:

Originally Posted by phenyloxime (Post 3709009)
I think I have encountered precisely what johnsfine just said. When I add a printf line, to look at the address of each variable, The problem dissappears:

I don't think that is what I said. Be careful about "disappears". Sometimes a bug has no symptom. That doesn't mean there is no bug.

Code:

  short M;
...
    scanf("%u",&M);

That is a bug. As others have explained, the format %u is too big for the type short. The two bytes immediately after M in memory do get clobbered.

Any change that makes the "problem disappear" just means there is no symptom to clobbering those two bytes.

Quote:

How would I find out the addressing of these variables without printing them?
You could use a debugger (gdb) if you know how.

Quote:

Are the actual addresses of variables located somewhere in the compiled binary?
No. These are local variables, so their addresses (if they even have addresses) are computed at run time relative to the stack.
If you knew assembler language, you could dump a disassembly of the compiler binary and see the relative addresses of the variables. In this case, that is what you actually care about, not their absolute addresses.

From what you have posted so far, the compiler you are using seems to allocate M first and then i when you don't use &i in that printf, but it allocates i first and then M when you do. When you don't have that printf, an optimizing compile would probably only allocate M. i wouldn't even have an address, because the function is so simple i could be in a register.

orgcandman 10-06-2009 12:20 PM

Quote:

Originally Posted by Wim Sturkenboom (Post 3709338)
You don't want to care about that; that's what high level languages are for. Just use the proper types or the %hd as per my previous post. I you want to care about those things, use assembly ;)

The only time that you need to be aware of it is if you want to dump data from e.g. a file or serial port into a struct.

I'd suggest wiki-ing Buffer Overflow vulnerabilites.

Wim Sturkenboom 10-06-2009 12:55 PM

Why :scratch: My reply was related to How would I find out the addressing of these variables without printing them? Are the actual addresses of variables located somewhere in the compiled binary?


All times are GMT -5. The time now is 07:11 AM.