Thread: Coverting array to string

  1. #1
    Registered User
    Join Date
    Mar 2008
    Posts
    8

    Coverting array to string

    Hey everybody!

    I started learning C a few weeks ago, and I wanted to try and learn the underlying language features without using the foundation framework, so I've been dealing with strings by hand. It's been difficult to say the least, but it seems to have helped solidify some of the concepts of memory management and variable types (although in truth I'm still not sure how well I understand!). At any rate, everything was going smoothly until I ran into something which I cannot for the life of me debug. This may be a bit long winded, but I have tried to cut down on any superfluous information.

    Essentially what I'm trying to do is get input from the user (via fgets), and then, based on what the user typed, execute commands. So, fgets saves the users input to a character array "gInput" (a global variable), and I check if it matches whatever command I want by invoking the following method. For example, one of my statements is:

    Code:
    if ( checkInput("north") || checkInput("n") ) { [currentPlayer move: "north"]; }
    The checkInput method is...

    Code:
    int checkInput (char * check) {
      int i = 0;
      int same = 1; // assume they are the same.  this may be disproven later.
      extern char gInput[50];
     
      if ( gInput[i] == '\n' || gInput[i] == '\0' ) { same = 0; } // so that no input does not return as the same
      
      for ( i = 0; gInput[i] != '\n' && gInput[i] != '\0'; i++ ) { // until you find a newline or null char
          if ( gInput[i] != check[i]) { same = 0; }
      }
      
      if ( check[i] != '\0' ) { same = 0;} // to prevent ea from returning as the same as east, etc.
      
      if ( same == 1 ) { gMatched = 1; return 1;} else { return 0; }
    }
    Now, this works fine and well, however I needed something that would do more than simply tell me if two strings were the same. I needed the user to be able to input a command such as 'get short sword', and have something that would realize that the user was invoking the get command on the object short sword. To accomplish this, I wrote this. There are ultimately only going to be a limited number of commands, so I didn't mind parsing them manually via array[index] == 'letter', although is there a better way to do this? This method is invoked by this command...

    Code:
    if ( checkCommand() == "get") { get(currentPlayer); }
    And the checkCommand() method is...

    Code:
    char* checkCommand () {
      int i = 0;
      extern char gInput[50];
      extern char gSecondWord[50];
      if ( gInput[0] == 'g' && gInput[1] == 'e' && gInput[2] == 't' && gInput[3] == ' ' ) { 
        gMatched = 1;
        i = 4;
        for ( i = 4; gInput[i] != '\n' && gInput[i] != '\0'; i++ ) {
          gSecondWord[i-4] = gInput[i];
        }
      gSecondWord[i-4] = '\0';
      return "get";
      }  
      if ( gInput[0] == 'd' && gInput[1] == 'r' && gInput[2] == 'o' && gInput[3] == 'p' && gInput[4] == ' ') { 
        gMatched = 1;
        i = 5;
        for ( i = 5; gInput[i] != '\n' && gInput[i] != '\0'; i++) {
          gSecondWord[i-5] = gInput[i];
        }
      gSecondWord[i-5] = '\0';
      return "drop";
      }  
    }
    So basically, if the command parses get, then it runs the get method.. if parses drop, then it runs the drop method. (ultimately I will expand this to commands such as "look" and "fight", however I imagine this will be straightforward)

    So here is where we run into the problem that I just cannot understand.

    The get method works perfectly.

    Code:
    void get (Player * currentPlayer) {
      extern char gResult[100];
      sprintf(gResult, "There is nothing here by that name.");
      extern Room *gRooms [10][10];
      extern char gSecondWord[50];
      char *secondWord;
      sprintf(secondWord, "%s", gSecondWord);
      char *itemName;
      extern int times;
      times = 0;
      int done = 0;
      for ( times = 0; times <= 9 && done == 0; times++ ) {
            if ([gRooms[[currentPlayer retRow]][[currentPlayer retCol]] retItem]) {
    	  itemName = [[gRooms[[currentPlayer retRow]][[currentPlayer retCol]] retItem] retName];
              if (CheckStrings (itemName, secondWord) ) {
                done = 1;
    	    [currentPlayer claimThing: [gRooms[[currentPlayer retRow]][[currentPlayer retCol]] retItem]];
    	    }
              }
           }
      }
    But the drop command is doing something weird. Everything seems to be pretty much the same as the get command, and yet if I remove one of the lines which I can't see as legitimately serving any purpose, I get a Bus Error (I have indicated which line via a comment in the code). With the line though, the code runs perfectly. I can pick up items, move to a new room, drop them, pick them up later.. it seems to be running fine.

    Code:
    void drop (Player * currentPlayer) {
      extern char gResult[100];
      sprintf(gResult, "You are carrying nothing by that name.");
      extern char gSecondWord[50];
      char *secondWord;
      sprintf(secondWord, "%c", gSecondWord[0], gSecondWord[1], gSecondWord[2], gSecondWord[3], gSecondWord[4]);
    // I don't understand why the above line should make a difference!
      sprintf(secondWord, "%s", gSecondWord);
      char *itemName;
      extern int times;
      times = 0;
      int done = 0;
      for ( times = 0; times <= 9 && done == 0; times++ ) {
            if ([currentPlayer retItem]) {
    	itemName = [[currentPlayer retItem] retName];
              if (CheckStrings (itemName, secondWord) ) {
              done = 1;
    	  [currentPlayer releaseThing: [currentPlayer retItem]];
    	  }
            }
    
      }
    }
    I am befuddled. With the line, the program seems to run perfectly. Remove it though, and I get a bus error. The weird thing is, the get command works perfectly even without this strange command. I feel like my code must be unstable if I have to invoke work arounds like this!

    Thank you very much for taking the time to read over this. Does anybody have any thoughts?

  2. #2
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Just declaring
    Code:
    char *secondWord;
    doesn't give you any room to actually put a string in. You need to make that pointer point to memory you own. If you don't have any memory, you need to get some -- easiest way here is to change the above to
    Code:
    char secondWord[50];
    The name "secondWord" by itself will then decay to a pointer to the array and everybody is happy.

    You should also note that the "interesting" sprintf will only every print one character (the fact that you give it five characters to print is completely irrelevant -- your format string says one character only, so one character it is). This is probably why it doesn't trash memory -- you might be able to get away with changing one byte at wherever secondWord points to, but not 50 bytes. It shouldn't work in get either.

    Eventually you will notice strcmp and strcpy.

  3. #3
    Dr Dipshi++ mike_g's Avatar
    Join Date
    Oct 2006
    Location
    On me hyperplane
    Posts
    1,218
    Code:
    if ( checkCommand() == "get") { get(currentPlayer); }
    This looks wrong. In C you don't compare strings like this. Maybe use strcmp.

  4. #4
    Registered User
    Join Date
    Mar 2008
    Posts
    8
    Quote Originally Posted by tabstop View Post
    Code:
      sprintf(secondWord, "&#37;c", gSecondWord[0], gSecondWord[1], gSecondWord[2], gSecondWord[3], gSecondWord[4]);
    You should also note that the "interesting" sprintf will only every print one character (the fact that you give it five characters to print is completely irrelevant -- your format string says one character only, so one character it is). This is probably why it doesn't trash memory -- you might be able to get away with changing one byte at wherever secondWord points to, but not 50 bytes. It shouldn't work in get either.
    Thank you for reminding me!

    That was one of the weirdest parts. Even though there's only one %c, If I remove even one of the arguments gSecondWord[0], gSecondWord[1] ... then I get a bus error. Adding gSecondWord[5] and above doesn't seem to have any impact, but removing any one of them and the code breaks!

    EDIT: I made the change you suggested (char *secondWord to char secondWord[50]) and it works like a charm. I'm still very confused as to why I got the results that I did (not that it didn't work, but that it worked in one method but not the other, and was fixable by random hacks...), but thank you again for the help!
    Last edited by do_kev; 03-13-2008 at 03:12 PM.

  5. #5
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by do_kev View Post
    Thank you for reminding me!

    That was one of the weirdest parts. Even though there's only one %c, If I remove even one of the arguments gSecondWord[0], gSecondWord[1] ... then I get a bus error. Adding gSecondWord[5] and above doesn't seem to have any impact, but removing any one of them and the code breaks!
    Different symptom of the same problem.

  6. #6
    Registered User
    Join Date
    Mar 2008
    Posts
    8
    Given how many compiler errors can arise from a simple omission, I should have guessed. =)

    Thanks again!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. String issues
    By The_professor in forum C++ Programming
    Replies: 7
    Last Post: 06-12-2007, 09:11 AM
  2. Program using classes - keeps crashing
    By webren in forum C++ Programming
    Replies: 4
    Last Post: 09-16-2005, 03:58 PM
  3. Calculator + LinkedList
    By maro009 in forum C++ Programming
    Replies: 20
    Last Post: 05-17-2005, 12:56 PM
  4. Quick question about SIGSEGV
    By Cikotic in forum C Programming
    Replies: 30
    Last Post: 07-01-2004, 07:48 PM
  5. Warnings, warnings, warnings?
    By spentdome in forum C Programming
    Replies: 25
    Last Post: 05-27-2002, 06:49 PM