Thread: Newbie question

  1. #1
    Registered User
    Join Date
    May 2011
    Posts
    12

    Newbie question

    Code:
    #include <stdio.h>
    #include <string.h>
    #include <cstdlib>
    
    int length, i, intNumber, sum, power = 1;
    char number[8], sWhich[1], which = 'n';
    
    int main(){
    	printf("Type in a number: ");
    	gets(number);
    	length = strlen(number);
    	
    	if (number[0] == '0'){
    		which = 'b';
    		for (i=1; i<length; i++){
    			if (number[i] > 49 || number[i] < 48){
    				printf("That is an invalid number!");
    				exit(1);
    			}
    		}
    	}
    	
    	for (i=0; i<length; i++){
    		if (number[i] > 49 && number[i] < 58){
    			if (which = 'n') {
    				which = 'd';
    			}
    		}else if (number[i] < 48 || number[i] > 57){
    			printf ("That is an invalid number!");
    			exit(1);
    		}
    	}
    
    	if (which == 'n'){
    		printf("Is this number decimal (d) or binary (b)? ");
    		gets(sWhich);
    		which = sWhich[0];
    		number[0] = 49;    /* Why is this necessary? number[0] becomes null otherwise */
    	}
    	
    	sum = 1;
    	for (i=length-1; i>=0; i--){
    		intNumber += ((number[i] - 48) * sum);
    		sum *= 10;
    	}
    
    	if (which == 'd' && intNumber > 255){
    		printf("That is an invalid number!");
    		exit(1);
    	}
    	
    	if (which == 'b'){
    		sum = 0;
    		power = 1;
    		for (i=length - 1; i>=0; i--){
    			if (number[i] == 49){
    				sum += power;
    			}
    			power *= 2;
    		}
    		printf("Converting binary to decimal. Answer is: %d", sum);
    	}
    	
    	if (which == 'd'){
    		printf("Converting decimal to binary. Answer is: ");
    		sum = 128;
    		for (i=0; i<8; i++){
    			if (intNumber >= sum){
    				printf("1");
    				intNumber -= sum;
    			}else{
    				printf("0");
    			}
    			sum /= 2;
    		}
    	}
    }
    This is a simple binary/decimal converter. As per the comment, if I don't include the assignment "number[0] = 49", number[0] resets to null. If the program doesn't encounter "which = 'd'", then number[0] stays at whatever value the user assigned to it. I don't understand how or why gets(sWhich) or which=sWhich[0] is resetting number[0].

    It works, but I'd like to avoid this in future, so any help much appreciated. Also don't be afraid to criticize my likely redundancies

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,667
    > if (which = 'n')
    Try using ==

    > number[0] = 49; /* Why is this necessary? number[0] becomes null otherwise */
    And why does it do that?
    Because sWhich is just a single char, and gets() will write at least TWO bytes to whatever array you pass in (one byte is always the \0 to mark the end of the string).

    Other comments.
    1. Do NOT use gets() to read user input.
    SourceForge.net: Gets - cpwiki

    2. Remove all those global variables.

    3. You validate a binary number first, then give the user the option of saying it's a binary number with no further checks.

    4. The two blocks of code from line 50 onwards should be two separate functions, so main would be
    Code:
    if (which == 'b') {
        doBinary(number);
    }
    // ditto for decimal
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    May 2011
    Posts
    12
    Quote Originally Posted by Salem View Post
    Try using ==
    You are amazing. And your comments are invaluable. Thank you so much!

    Edit: While it works (which == 'n' did the trick), I still don't understand why. Or what sWhich has to do with number[0] on lines 36-38. I'm sure it's right in front of me
    Last edited by Gareth321; 03-21-2012 at 06:40 AM.

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,667
    > char number[8], sWhich[1], which = 'n';
    How many characters can you store in sWhich - INCLUDING the \0?

    Where do you think any extra characters will go?

    Since it seems from your code that overrunning the end of sWhich trashes number, then try typing something stupidly long like "1111111111111111" and see what happens. This would also demonstrate why you should NEVER use gets()
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    Registered User
    Join Date
    May 2011
    Posts
    12
    Wait, the overflow runs into other global variables?? I had no idea. I'll be sure to steer clear of gets in future. Thanks again.

  6. #6
    Registered User
    Join Date
    Dec 2011
    Posts
    795
    The overflow can "safely" overrun anything your program owns in memory. The only reason why the program should crash is if it tries to write to protected memory.

    For example, if you use gets() on the stack:
    Code:
    char array[5];
    char array2[5];
    
    gets(array);
    And enter a ten-character string, the rest will most likely end up in array2.

    If you have it on the stack with nothing to catch it:
    Code:
    char array[5];
    
    gets(array);
    It will most likely end up overwriting the stack base pointer and return variable, as stack variables are stored backwards as an offset of the base pointer:
    Code:
    push %rbp /* pushes base to stack */
    movl %rsp, %rbp /* base ptr = stack ptr */
    movl $0, -0x4(%rbp) /* your array, offset by 4 (first four = return variable) */
    
    /* if I wanted to access array[4] */
    movl $0, -0x5(%rbp) /* stored backwards, series of five one-byte types */
    
    /* so if gets() overwrites that, into array[6], for example.. */
    movl $0, -0x3(%rbp) /* wut! this is modifying the return variable! */
    
    /* now lets say it keeps going, and writes into array[9] */
    movl $0, (%rbp) /* now, you just overwrote your base pointer */
    You can see what happens if this continues.

  7. #7
    Registered User
    Join Date
    May 2011
    Posts
    12
    Mayhem. Thanks for clarifying. I think I'll be sticking to fgets in future

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Question from a Newbie
    By kiddo in forum C Programming
    Replies: 7
    Last Post: 02-27-2010, 06:05 PM
  2. Newbie with Very Newbie Question
    By Jedi_Mediator in forum C++ Programming
    Replies: 18
    Last Post: 07-01-2008, 08:00 AM
  3. question from a newbie
    By yoda05378 in forum C Programming
    Replies: 3
    Last Post: 05-12-2007, 04:52 AM
  4. C++ newbie / linux not so newbie question
    By goldmonkey in forum C++ Programming
    Replies: 7
    Last Post: 12-13-2003, 12:27 PM
  5. newbie question about i/o!!!!!!!!help!!!!11
    By incognito in forum C++ Programming
    Replies: 7
    Last Post: 03-14-2002, 09:48 PM