Thread: File I/O with arrays

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Registered User
    Join Date
    Sep 2006
    Posts
    27

    File I/O with arrays

    Yet another newbie-ish problem.... this time slightly more advanced.

    I'm having a bit of trouble reading information as text from a file.... The information involves three different sets of integers, two normal, and one an array, like so:

    Code:
    100
    30
    1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111131111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111111111111111111111111111111111111111111111111111111111111111131111111111111111111
    1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111111111111111111111111111222222221111111111111111111111111111111111111111111111111
    1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111131111111111111111111111111222222221111111111111111111111111111111111111111111111111
    1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111111111111111111111111111111131111111111111111111111111111111111111111111111111111
    1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111111111111111111111111111111111111111111111111111111111113111111111111111111111111
    1111111111111111113111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111111111111111111111111111111111311111111111111111111111111111111111111111111111111
    1111111111111111111111111111131111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111111111111111111111111111111111111111111111111111111111111111111111311111111111111
    1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    Yes, it's a lot, but I'm trying to hard-code something for testing.

    My file I/O operation currently reads like so:-

    Code:
    int location::fileread(char filename[10])
    {
        ifstream a_file ( filename );
        if ( !a_file.is_open() ) {
        cout<<"File could not be opened./n";
        return 0;
          }
    else {
        a_file>>mapx;                              //read the first value, the x-value
        a_file>>mapy;                              //read the second value, the y-value
        a_file>>terrain[mapx][mapy];      //store the long section of 1s, 2s, and 3s in terrain[100][30]
        return 1;}
    }
    This results in me getting a blank screen with no information whatsoever. I don't know if this means that the x and y values are being read but the array isn't, or if the whole lot is horribly wrong (the results would, I think, be pretty much the same). I'm pretty sure the problem lies in the array. Does instreaming read a single character? Multiple characters? The entire line? Is there any way to alter this?

    It's probably a really stupid question, but any help would be greatly appreciated!

  2. #2
    Registered User
    Join Date
    Nov 2005
    Posts
    545
    Erm, why are you returning 1 after the else statement as that means that there is an error. Return 1 if the file can't be opened.

  3. #3
    Registered User
    Join Date
    Sep 2006
    Posts
    27
    To be honest, I just prefer it that way.... the main() setup goes something like so:

    Code:
    int main()
    {
        char mapf[10];
        cout<<"Enter map file:\n";
        cin>>mapf;
        if (locate.fileread(mapf) == 1){
        clrscr();
        charx = mapx/2;
        chary = mapy/2;
        mapprint(mapx, mapy);
        do {
            input();
            }
            while (input() != 0) ;
            clrscr();
            }
            else {
        cursorpos(0,0);
        cout<<"Goodbye!";}
    }
    I just have a thing about 1 being 'true' and 0 being 'false'. It's not that much trouble to change, though, if you think I should.

  4. #4
    Registered User
    Join Date
    Sep 2006
    Posts
    27
    Hmm, thanks for the advice Salem, but it's still not loading correctly . Maybe I should figure out how the C commands work rather than mess around with the C++ commands... although the C version seems so much more complex.

    EDIT:
    I've figured out how to manage it, rather than storing each variable in a two dimensional way in the file itself, I have to store it one on top of the other (like
    1
    1
    1
    1
    1
    1
    1
    etc...) and then read it like that. Unless there's some way to integrate strings and integers.... anyway, for the time being, problem solved.
    Last edited by 20,000leeks; 09-17-2006 at 07:10 AM.

  5. #5
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >Maybe
    Code:
    for ( int r = 0 ; r < mapy ; r++ ) {
      for ( int c = 0 ; c < mapx ; c++ ) {
        a_file>>terrain[r][c];
      }
    }
    Maybe not. It looks like all of the digits are intended to be unique entities but they're not separated by whitespace. a_file>>terrain[r][c] is unlikely to work as expected in this situation. Something more like this would work if I'm judging the file properly:
    Code:
    a_file>> first;
    a_file>> second >> ws;
    
    for ( int i = 0; i < mapy; i++ ) {
      for ( int j = 0; j < mapx; j++ )
        terrain[i][j] = a_file.get() - '0';
    }
    My best code is written with the delete key.

  6. #6
    Registered User
    Join Date
    Sep 2006
    Posts
    27
    Hmm, it *almost* works. I think because there's a white space on the end of each line, that makes things a little more complex, so I tried:

    Code:
    for ( int i = 0; i < mapy; i++ ) {
           for ( int j = 0; j < mapx; j++ )
            if ( j < mapx){
            terrain[j][i] = a_file.get() - '0';
            }
            else a_file>> terrain [j][i];
           }

    but it still comes out on a slant (like this

    Code:
     .................................................
    . ................................................
    .. ...............................................
    ... ..............................................
    .... .............................................
    ..... ............................................
    ...... ...........................................
    ....... ..........................................

  7. #7
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,666
    > a_file>>terrain[mapx][mapy]
    This refers to the element just off the end of the array

    Maybe
    Code:
    for ( int r = 0 ; r < mapy ; r++ ) {
      for ( int c = 0 ; c < mapx ; c++ ) {
        a_file>>terrain[r][c];
      }
    }
    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.

  8. #8
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    You need to read in the '\n', I think.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  9. #9
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    You could just do this:
    Code:
    for ( int i = 0; i < mapy; i++ ) {
      for ( int j = 0; j < mapx; j++ )
        terrain[i][j] = a_file.get() - '0';
    
      while(a_file.get() != '\n' && !a_file.bad());
    }
    .bad() might not be the best function to use however.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  10. #10
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >You could just do this:
    Handling the linebreak outside of the inner loop is definitely a better solution, but I'd still want some error checking:
    Code:
    for ( int i = 0; i < mapy; i++ ) {
      for ( int j = 0; j < mapx; j++ ) {
        char ch;
    
        if ( !a_file.get ( ch ) ) {
          // Handle an input error
        }
    
        terrain[i][j] = ch - '0';
      }
    
      a_file.ignore();
    }
    My best code is written with the delete key.

  11. #11
    Registered User
    Join Date
    Sep 2006
    Posts
    27
    Aha! Problem solved! Thanks a lot, I'd probably have resorted to using a single-column file otherwise....

  12. #12
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    I forgot about ignore() . . .

    I'm sure you've fixed this by now, but here's an earlier line you posted:
    Code:
    cout<<"File could not be opened./n";
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  13. #13
    Registered User
    Join Date
    Sep 2006
    Posts
    27
    Ah, yes, I noticed that one about five minutes after posting it.... I guess there's an upside to uncomplicated applications, you catch typos faster.

  14. #14
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >I guess there's an upside to uncomplicated applications, you catch typos faster.
    Not really, you just have fewer of them to deal with.
    My best code is written with the delete key.

  15. #15
    Registered User
    Join Date
    Sep 2006
    Posts
    27
    True. The bigger this thing gets, the more trouble I have finding out what exactly the problem is. I think soon I will have to split it into multiple files...

    Still, at the moment I can read a map (albeit with a bit of buggy display sometimes) and open and close a door. This much has taken me over two days. It's kind of daunting.

    Still, two more questions (I'm way out of my depth here) -

    1.When reading from (or generating, for that matter) a map that doesn't fill the entire size I allocate for it, I sometimes get anomalous terrain types displaying off the edges. This has no effect on screen-size maps or gameplay, but it looks... ugly. My location printing code goes something like this:

    Code:
    void location::printloc(int x1, int y1, int x, int y)
    {
         cursorpos(x,y);
         if (monst[x1][y1] < 1){                                      //checks to see if there is a monster of some type at location
                            if (item[x1][y1][0] < 1){                 //ditto items
                                           if (build[x1][y1] < 1){    //ditto buildings
                                                           if (terrain[x1][y1] == 1){     //ditto terrain
                                                                             textcolor(7);
                                                                             cout<<".";
                                                                             }
                                                           else if (terrain[x1][y1] == 2) {
                                                                             textcolor(15);
                                                                             cout<<"#";
                                                                             }
                                                           else if (terrain[x1][y1] == 3) {
                                                                             textcolor(2);
                                                                             cout<<"T";
                                                                             }
                                                           else if (terrain[x1][y1] == 4) {
                                                           textcolor(6);
                                                           cout<<"+";
                                                           }
                                                           else if (terrain[x1][y1] == 5) {
                                                           textcolor(6);
                                                           cout<<"-";
                                                           }
                                                           else cout<<" ";
                                                           }
                                           else cout<<" ";
                                           }
                            else cout<<" ";
                            }
         else if (monst[x1][y1] == 99){
              textcolor(15);
              cout<<"@";
              }
         else {
              textcolor(7);
              cout<<" ";
              }
         textcolor(7);
    }
    whereas the overall map-printer is as follows:

    Code:
    int mapprint(int mapx, int mapy) //function to display the map as a whole
    { 
        int x(0); //sets the cursor to the top left edge.
        int y(0);
        locate.set_char(charx,chary);
        
        while (y < 30) {                  //This may seem odd, but not all of the map is being displayed.
              while (x < 100) {         //This way, items/monsters/whatevers can be offscreen
                     locate.printloc(xdisp, ydisp, x, y);
                     x++;
                     xdisp++;
                     }
              x = 0;
              xdisp = mapx/2 - 50;  //resets the map width display
              y++;
              ydisp++;
              }
              return 0;
    }
    As far as I can tell, the printing function shouldn't even get called outside the map boundaries, let alone actually place anything there (the terrain values for those locations are unspecified).


    2.My quit function is a little buggy, it won't always register a keypress

    Code:
    else if (inputchar == 'q'){
                   cursorpos(0,31);
                   cout<<"Are you sure you want to quit?";
                   inputchar = getch();
                   while(inputchar !='y' && inputchar != EOF){
                        cursorpos(0,31);
                        cout<<"Quit cancelled.";
                        return 1;
    In this instance, it *should* wait for any keypress at all, and if not 'y', print the "quit cancelled" message. However, sometimes it ignores a y keypress or doesn't register any keypress whatsoever. Is this due to the getch() function, or am I using the while loop incorrectly?

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Subtle(?) File I/O Problem
    By cecomp64 in forum C Programming
    Replies: 9
    Last Post: 07-16-2008, 11:39 AM
  2. Formatting the contents of a text file
    By dagorsul in forum C++ Programming
    Replies: 2
    Last Post: 04-29-2008, 12:36 PM
  3. Can we have vector of vector?
    By ketu1 in forum C++ Programming
    Replies: 24
    Last Post: 01-03-2008, 05:02 AM
  4. File I/O Question
    By Achy in forum C Programming
    Replies: 2
    Last Post: 11-18-2005, 12:09 AM
  5. simulate Grep command in Unix using C
    By laxmi in forum C Programming
    Replies: 6
    Last Post: 05-10-2002, 04:10 PM