Thread: sprintf corrupted output using string as argument

  1. #1
    Registered User
    Join Date
    Apr 2011
    Posts
    8

    sprintf corrupted output using string as argument

    Hi everyone,

    I have searched high and low for the answer to what I am sure is a simple mistake that I just can't put my finger on!

    When using the %s argument with sprintf to pass a string of characters, the resulting output is unexpected and the rest of the argument calls are also corrupted. I have tried to specify the precision using something like %.4s to read four characters but the same thing happens.

    Code:
    #include <string>
    #include <iostream>
    using namespace std;
    
    class testclass
    {
    	public:
    		testclass(string id, int firstnumber, int secondnumber, int thirdnumber);
    		~testclass();
    };
    
    testclass::testclass(string id, int firstnumber, int secondnumber, int thirdnumber)
    {
    	char statement[100];
    	sprintf_s(statement, "%s, %i, %i, %i", id, firstnumber, secondnumber, thirdnumber);
    
    // statement should now say: "abcd, 1, 2, 3"
    // statement actually says: "¸ý$, 1684234849 1537765632 44"
    
    	cout << statement;
    }
    
    int main()
    {
    	new testclass("abcd", 1, 2, 3);
    	return 0;
    }
    I know I am going to kick myself for this one!

  2. #2
    Registered User
    Join Date
    Aug 2010
    Location
    Poland
    Posts
    733
    sprintf is a function from C standard library and it works with C-style strings. You should give up C style functions and use C++ equivalents (std::cout, std::cin and others), which are less error-prone and provide better compile-time type checking. But to fix this one, use c_str() method:

    Code:
    // do not use extensions when unnecessary (sprintf_s)
    sprintf(statement, "%s, %i, %i, %i", id.c_str(), firstnumber, secondnumber, thirdnumber);

  3. #3
    Registered User
    Join Date
    Dec 2007
    Posts
    2,675
    How does that even compile? A std::string is not the same as the char * sprintf expects. You need to use the c_str() method of the std::string class to get the underlying char *.

    A better option would be to use a strings and a stringstream, instead of dragging C char arrays and I/O functions like sprintf into the picture:

    Code:
    #include <string>
    #include <iostream>
    #include <sstream>
    
    using namespace std;
    
    class testclass
    {
    public:
        testclass(const string &id, const int firstnumber, const int secondnumber, const int thirdnumber);
        ~testclass();
    };
    
    testclass::testclass(const string &id, const int firstnumber, const int secondnumber, const int thirdnumber)
    {
        stringstream ss;
        ss << id << ", " << firstnumber << ", " << secondnumber << ", " << thirdnumber;
        // Get the string from the stringstream and print it                        
        cout << ss.str() << endl;
    }
    
    int main()
    {
        new testclass("abcd", 1, 2, 3);
        return 0;
    }

  4. #4
    Registered User
    Join Date
    Aug 2010
    Location
    Poland
    Posts
    733
    Quote Originally Posted by rags_to_riches View Post
    How does that even compile? A std::string is not the same as the char * sprintf expects. You need to use the c_str() method of the std::string class to get the underlying char *.

    A better option would be to use a strings and a stringstream, instead of dragging C char arrays and I/O functions like sprintf into the picture:
    Is there any reason to add const-qualifier to these ints passed by value?


    Code:
    int main()
    {
    	delete new testclass("abcd", 1, 2, 3);
    	return 0;
    }
    Better

    Code:
    int main()
    {
    	testclass test("abcd", 1, 2, 3);
    	return 0;
    }
    Much better

  5. #5
    Registered User
    Join Date
    Dec 2007
    Posts
    2,675
    Is there any reason to add const-qualifier to these ints passed by value?
    Reason? Not really, but I'm a const-fanatic!

  6. #6
    Registered User
    Join Date
    Apr 2011
    Posts
    8
    Quote Originally Posted by kmdv View Post
    testclass test("abcd", 1, 2, 3);
    [/code]
    Unfortunately the main part of the code generates objects on-the-fly so I can't do this

    Quote Originally Posted by rags_to_riches
    A better option would be to use a strings and a stringstream, instead of dragging C char arrays and I/O functions like sprintf into the picture
    Thanks! Stringstream class objects seem to be a lot easier to manage for what I'm trying to do, as a lot of values from other variables end up pulled into my statement string.

    I did hit a little snag, the statement is eventually passed as an SQL query through ODBC, and the function for doing this, SQLExecDirect(), expects a SQLCHAR* for the statement input. It didn't like using &ss.str() I worked around it by copying the stringstream output to a string as below and used string.c_str(), but is there a tidier way to use the stringstream object directly?

    Code:
    	
    stringstream statement;
    statement <<  "INSERT INTO tables.tables VALUES ('" << this->uniqueID << "', " << "'test'" << ", " << this->numbers_and_stuff)";
    string teststring;
    teststring = statement.str();
    sqlReturn = SQLExecDirect( sql_hStmtObj, (SQLCHAR*)teststring.c_str(), SQL_NTS);
    //this works ok

  7. #7
    Registered User
    Join Date
    Dec 2007
    Posts
    2,675
    statement.str() returns a std::string object; therefore, calling .c_str() on this object returns the const char *
    Code:
    statement.str().c_str()

  8. #8
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    A third approach might be Boost.Format. It's even more extensive than sprintf and family on formatting.
    Also, don't cast to SQLCHAR*. If you've done it right, there will be no need for casting. If it doesn't work, then you did something wrong (I can't imagine a cast being required).
    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.

  9. #9
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,817
    FWIW/FYI, on the correct use of the sprintf_s function:
    Quote Originally Posted by http://msdn.microsoft.com/en-us/library/ce3zzk1k.aspx
    The other main difference between sprintf_s and sprintf is that sprintf_s takes a length parameter specifying the size of the output buffer in characters. If the buffer is too small for the text being printed then the buffer is set to an empty string and the invalid parameter handler is invoked. Unlike snprintf, sprintf_s guarantees that the buffer will be null-terminated (unless the buffer size is zero).
    This argument is the second one and looks something like:
    Code:
    char buff[100];
    ...
    sprintf_s(buff,sizeof(buff),"Hello %s, how are you today?",my_name);
    "Owners of dogs will have noticed that, if you provide them with food and water and shelter and affection, they will think you are god. Whereas owners of cats are compelled to realize that, if you provide them with food and water and shelter and affection, they draw the conclusion that they are gods."
    -Christopher Hitchens

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. sprintf with dynamic string
    By Ducky in forum C++ Programming
    Replies: 16
    Last Post: 09-17-2010, 02:32 PM
  2. sprintf output error
    By Ji33my in forum C++ Programming
    Replies: 2
    Last Post: 09-16-2010, 10:53 PM
  3. Stack around the variable 'Output' was corrupted
    By jacksb68 in forum C Programming
    Replies: 5
    Last Post: 09-08-2009, 08:55 AM
  4. string equivalent of sprintf()
    By e66n06 in forum C++ Programming
    Replies: 4
    Last Post: 08-16-2007, 03:30 PM
  5. global string gets corrupted
    By impz in forum C Programming
    Replies: 2
    Last Post: 08-08-2007, 05:28 AM