P.S. People asked if this is a homework assignment... It's not - developers at my company want to use this to debug output of their project.
If it's not homework, and this is under Linux, why not use the included "sort" program?
E.g.:
% printf 'D\x00C\x00\x00B\x00A' | sort -z | od -c
0000000 \0 A \0 B \0 C \0 D \0
0000011
FSF/GNU sort offers the -z option:
-z, --zero-terminated
end lines with 0 byte, not newline
Amended to add:
Okay, seeing as of how you still want your own code...
And seeing as of how no one else has yet posted an STL-based approach.
Note the use of struct FUNCTOR for the comparison (via stl::sort()). And, if you want, you could always use ostream_iterator<string>(cout, "\n") instead to make things a little more human-readable..
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
/* ifstream won't set EOF-state until we try to read past the end-of-file.*/
/* (Makes for lots of grief trying to read in files...) */
inline bool
IsStreamStillGood( istream & theStream )
{
return theStream && (theStream . peek() != EOF);
}
template<class TYPE> inline void DELETE( TYPE * x)
{
delete x;
x = (TYPE *) NULL;
}
struct FUNCTOR
{
bool operator()(const string & x, const string & y) { return x < y; }
};
int
main(int argc, char **argv)
{
istream * stream;
vector<string> v;
UASSERT( argc, >, 1 );
const int recordSize = atoi( argv[1] );
char buffer [ recordSize + 1 ];
UASSERT( recordSize, >, 0 );
if ( argc > 2 )
stream = new ifstream( argv[2] );
else
stream = & cin;
while ( IsStreamStillGood( * stream ) )
{
stream-> read( buffer, recordSize );
v.push_back( string( buffer, stream->gcount() ) );
}
UASSERT( v.back().size(), ==, size_t(recordSize) );
FUNCTOR functor;
sort( v.begin(), v.end(), functor );
copy( v.begin(), v.end(), ostream_iterator<string>(cout) );
if ( argc > 2 )
DELETE(stream);
}
Amended (again) to add:
Question regarding usage of strings in your STL approach: since there are potentially null characters ('\0') in the input, wouldn't strings get confused because of that? Someone suggested using char[] but I suspect the same problem would arise
If I have char c[10];, I'm free to say c[0] = '\0';. Same for c[1] or c[9]. I can have as many null characters in that array as I want. (Subject to the size of the array, of course.)
Now, when using c as a c-string, the question arises as to how long it is. Is it 1 character long or 9? Normally, in C, this is decided by where the first NULL character appears.
So things like printf(%s), scanf(%s), strncat(), strncpy(), strncmp(), etc aren't really happy with NULL ('\0') characters embedded within our binary data array.
But C++ std::string keeps track of the length independently. At least it seems to, and it permits things like: myString.append( 10, '\0' );
So, by using stream->read(buffer,recordSize) we read in a set number of chars (bytes). We don't really care whether they are nulls ('\0') or not. It's all good. Just give me recordSize number of bytes.
By creating with v.push_back(string(buffer, stream->gcount())), we push back a new string containing stream->gcount() chars (bytes). And again we don't care whether they are nulls ('\0') or not. We just need all stream->gcount() bytes.
Sort uses functor, which uses operator<(const string &, const string &), which uses string::compare(), which again will use the string's length and doesn't care about what data is actually contained in the string. Nulls ('\0') are just fine.
Now if we tried to use v.back().c_str(), well, then we have no length so the nulls would confuse us. But as long as we use the string object (e.g. v.back()) containing both data and length, we're good.
Which brings us to output. And again we are outputting the string, not myString.c_str(), so all the chars in the string are printed. Nulls ('\0') included.