Thread: Why does this function handle char* and char array differently?

  1. #1
    Registered User
    Join Date
    Mar 2015
    Posts
    184

    Why does this function handle char* and char array differently?

    Hi first post here

    I am playing around with text file IO to understand it better. Now I have a function that calls the read method of an ifstream object. It works when I pass an array to the function calling the read() method, but not when I pass a char*. Though the read() method takes a char* as input. I thought my array would decay to a char* when I passed it from main, so why do they work differently with read()?

    Here's a MWE, the program crashes due to one function call I commented.

    Code:
    #include <iostream>
    #include <fstream>
    #include <algorithm>
    
    
    template <class T>
    inline void checkfile(const T& ff){//basic opening check
        if ( (!ff.is_open()) || (!ff.good()) ){std::cerr<<"cant open file!!!\n";}
    }
    template <class T>
    inline void checkfile2(const T& ff){ //write & read check
        if (ff.fail()){std::cerr<<"Failed to read/write with file!!!\n";}
    }
    
    
    inline void readstuff(std::ifstream& ii, char* mytxt,const int S) //char array decays to char*
    {
        ii.seekg(0,std::ios::end);
        int N = std::min(int(ii.tellg()),S-1);
        ii.seekg(0,std::ios::beg);
        ii.clear(); //not sure if I need this
    
    
        ii.read(mytxt,N);
        //if (mytxt[S-1]!='\0'){mytxt[S-1]='\0';std::cout<<"\nInput char[] did not terminate with \\0, fixed it\n";}
    
    
    }
    
    
    inline void writestuff(std::ofstream& oo){
        oo.seekp(0,std::ios::beg); //reset setter
        oo << "bla bla  bla";
        oo << " more bla\n";
        oo << "yuup, bla with an extra \0 in it"; // operator<< terminates at \0 (what happens to last 6 chars?)
        oo << "this line moves the EOF again";
    
    
    }
    
    
    
    
    int main()
    {
    char mytxt[] = {'h','e','l','l','o','\0'}; //NB(!) cant take words > 5. Can not cast to char*.
    char* mytxt2 = "ABCDE"; //same size as mytxt (is it?)
    int sizetxt = int(sizeof(mytxt)/sizeof(mytxt[0]));
    
    
    std::ofstream oo("mydata.txt");
        checkfile(oo);
        writestuff(oo);
        checkfile2(oo);
    oo.close();
    
    
    std::ifstream ii("mydata.txt");
        checkfile(ii);
        readstuff(ii,mytxt2,sizetxt); //this statement makes it crash
        readstuff(ii,mytxt,sizetxt);
        checkfile2(ii);
    ii.close();
    
    
    std::cout << mytxt << std::endl; //bla b
    std::cout << mytxt2 << std::endl; //bla b
    
    
    return 0;
    }
    P.S. since I'm a newbie any style comments are also welcome

  2. #2
    Registered User
    Join Date
    Dec 2006
    Location
    Canada
    Posts
    3,229
    Code:
    oo << "yuup, bla with an extra \0 in it"; // operator<< terminates at \0 (what happens to last 6 chars?)
    There are 3 important things to realize here -

    1. string literals are treated as const char arrays.
    2. arrays are passed without size information to functions (they essentially "become" pointers to the first element)
    3. the << operator is really just a fancy way of calling a member function of "oo".

    So your code is really equivalent to this:
    Code:
    const char *str = "yuup, bla with an extra \0 in it";
    
    oo.operator<<(str);
    If the function doesn't know how long the string is (since it's passed as a pointer), how does it know when to stop reading?

    In C/C++, strings are assumed to be 0-terminated, so it simply keeps reading until it hits a '\0', then it stops.

    So the last 6 chars are ignored (actually 7, since there is also the automatically-added '\0' at the very end).

  3. #3
    Registered User
    Join Date
    Mar 2015
    Posts
    184
    Thank you. But my question still stands as the error occurs in the readstuff() function. And mytxt2 is not cast as a const char* during initialization right?

  4. #4
    Registered User
    Join Date
    Dec 2006
    Location
    Canada
    Posts
    3,229
    As for your actual question, it's because string literals are "const char *", and you are not allowed to modify them.

    In fact, if you turn up the warning level, it should warn you about this.

    Code:
    char mytxt[] = {'h','e','l','l','o','\0'}; //NB(!) cant take words > 5. Can not cast to char*.
    char* mytxt2 = "ABCDE"; //same size as mytxt (is it?)
    They are not the same.

    mytxt is a modifiable char array initialized to the string.
    mytxt2 is a pointer to a const string somewhere (determined by the compiler) that you may not have write access to.

  5. #5
    Registered User
    Join Date
    Mar 2015
    Posts
    184
    Thanks i get it, for some reason I was thinking about const* char instead of const char*. Also I have maximum warnings on, but it is a bit cryptic

  6. #6
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    I suggest that if you need a buffer, you use std::vector. If you need a string, you use std::string.
    std::vector is resizable, so if you take it by argument, resize it in your function to ensure it has enough storage. Don't leave it to the caller to avoid bugs.
    You can also create a vector locally, resize it, then return it. This is usually more preferred because it avoids have the caller create a buffer first.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  7. #7
    Registered User
    Join Date
    Mar 2015
    Posts
    184
    This was just learning by playing around. I have 2 other versions. One uses a stringstream object as a buffer with the buffer() method of the ifstream. The other version loads the ifstream directly into a string with the constructor and iterator arguments.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 2
    Last Post: 09-25-2014, 06:12 AM
  2. Replies: 2
    Last Post: 09-25-2014, 04:03 AM
  3. Replies: 8
    Last Post: 04-09-2013, 07:06 PM
  4. Replies: 2
    Last Post: 12-02-2012, 05:25 AM
  5. Replies: 3
    Last Post: 11-17-2008, 12:36 PM

Tags for this Thread