LinuxQuestions.org
Did you know LQ has a Linux Hardware Compatibility List?
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 10-03-2009, 10:09 PM   #1
phenyloxime
LQ Newbie
 
Registered: Sep 2009
Posts: 28

Rep: Reputation: 2
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.

Last edited by phenyloxime; 10-03-2009 at 10:28 PM.
 
Old 10-03-2009, 10:17 PM   #2
smeezekitty
Senior Member
 
Registered: Sep 2009
Location: Washington U.S.
Distribution: M$ Windows / Debian / Ubuntu / DSL / many others
Posts: 2,229

Rep: Reputation: 173Reputation: 173
M is not big enough so you are overwriting memory erasing i
try changing short M to long M
 
Old 10-03-2009, 10:24 PM   #3
lutusp
Member
 
Registered: Sep 2009
Distribution: Fedora
Posts: 835

Rep: Reputation: 101Reputation: 101
Quote:
Originally Posted by phenyloxime View Post
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.
 
Old 10-03-2009, 10:24 PM   #4
smeezekitty
Senior Member
 
Registered: Sep 2009
Location: Washington U.S.
Distribution: M$ Windows / Debian / Ubuntu / DSL / many others
Posts: 2,229

Rep: Reputation: 173Reputation: 173
Quote:
Originally Posted by phenyloxime View Post
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
 
Old 10-05-2009, 06:33 AM   #5
Wim Sturkenboom
Senior Member
 
Registered: Jan 2005
Location: Roodepoort, South Africa
Distribution: Slackware 10.1/10.2/12, Ubuntu 12.04, Crunchbang Statler
Posts: 3,786

Rep: Reputation: 282Reputation: 282Reputation: 282
%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$
 
Old 10-05-2009, 09:12 AM   #6
phenyloxime
LQ Newbie
 
Registered: Sep 2009
Posts: 28

Original Poster
Rep: Reputation: 2
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.
 
Old 10-05-2009, 09:23 AM   #7
johnsfine
Guru
 
Registered: Dec 2007
Distribution: Centos
Posts: 5,094

Rep: Reputation: 1111Reputation: 1111Reputation: 1111Reputation: 1111Reputation: 1111Reputation: 1111Reputation: 1111Reputation: 1111Reputation: 1111
Quote:
Originally Posted by phenyloxime View Post
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.
 
Old 10-05-2009, 10:10 PM   #8
phenyloxime
LQ Newbie
 
Registered: Sep 2009
Posts: 28

Original Poster
Rep: Reputation: 2
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?
 
Old 10-05-2009, 10:20 PM   #9
smeezekitty
Senior Member
 
Registered: Sep 2009
Location: Washington U.S.
Distribution: M$ Windows / Debian / Ubuntu / DSL / many others
Posts: 2,229

Rep: Reputation: 173Reputation: 173
JUST USE INT INSTEAD OF SHORT.
why not?
 
Old 10-06-2009, 05:02 AM   #10
Wim Sturkenboom
Senior Member
 
Registered: Jan 2005
Location: Roodepoort, South Africa
Distribution: Slackware 10.1/10.2/12, Ubuntu 12.04, Crunchbang Statler
Posts: 3,786

Rep: Reputation: 282Reputation: 282Reputation: 282
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.
 
Old 10-06-2009, 05:32 AM   #11
jiml8
Senior Member
 
Registered: Sep 2003
Posts: 3,171

Rep: Reputation: 114Reputation: 114
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.
 
Old 10-06-2009, 08:12 AM   #12
johnsfine
Guru
 
Registered: Dec 2007
Distribution: Centos
Posts: 5,094

Rep: Reputation: 1111Reputation: 1111Reputation: 1111Reputation: 1111Reputation: 1111Reputation: 1111Reputation: 1111Reputation: 1111Reputation: 1111
Quote:
Originally Posted by phenyloxime View Post
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.
 
Old 10-06-2009, 12:20 PM   #13
orgcandman
Member
 
Registered: May 2002
Location: dracut MA
Distribution: Ubuntu; PNE-LE; LFS (no book)
Posts: 594

Rep: Reputation: 102Reputation: 102
Quote:
Originally Posted by Wim Sturkenboom View Post
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.
 
Old 10-06-2009, 12:55 PM   #14
Wim Sturkenboom
Senior Member
 
Registered: Jan 2005
Location: Roodepoort, South Africa
Distribution: Slackware 10.1/10.2/12, Ubuntu 12.04, Crunchbang Statler
Posts: 3,786

Rep: Reputation: 282Reputation: 282Reputation: 282
Why 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?
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
MDADM deletes the disk contents upon initiation? alirezan1 Linux - Newbie 2 02-24-2009 12:37 PM
grep a shell script variable contents kushalkoolwal Programming 8 02-04-2009 06:15 AM
same system variable, but with different contents? kpachopoulos Linux - General 1 07-31-2005 05:15 PM
Can we specify variable field width in a scanf() format string? skie_knite007 Programming 3 05-13-2005 12:56 PM
get file contents with newlines into bash variable otoomet Linux - Software 2 01-06-2005 01:23 PM


All times are GMT -5. The time now is 03:18 AM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration