the characters in a c++ string are being ignored - c++

I'm trying to write to a hid device using signal11's hidapi (here).
In my troubleshooting, I've noticed that part of a string isn't being displayed to the console.
Here is a sample of my code
//device is a hid device and is assigned to in another part of the program.
//dataBuffer is a struct with only a char array called "buffer" and an int which is the size of the array called "size"
void DeviceCommands::Write(hid_device* device, dataBuffer* buf)
{
std::cout << "Attempting write >> buffer...\n";
buf->buffer[0] = 0;
std::cout << "Written to buffer...\n" << "writing buffer to device\n";
int res = hid_write(device, buf->buffer, sizeof(buf->buffer));
std::cout << "Write success: " + '\n';
std::cout << "Write complete\n";
}
I'm expecting for the console to return the following:
Attempting write >> buffer...
Written to buffer...
writing buffer to device
Write success: (0 if the write succeeds, -1 if it fails)
Write complete
But instead, this happens:
Attempting write >> buffer...
Written to buffer...
writing buffer to device
ess: Write complete
The "Write succ", result, and the line break are missing, I'm somewhat new to c++ but I have experience with c#. I'm just confused and some help would be much appreciated, thanks in advance and ask if you need more information!

This line:
std::cout << "Write success: " + '\n';
will print the string "Write success: " with an offset of 10 characters, which is the ascii value of \n. Hence you see ess on the screen.
You probably want:
std::cout << "Write success: " << res << "\n";
assuming res returns 0 or -1 as needed.

Do not 'add' a character to a string. It will not do what you expect.
Here you are thinking you are adding the line feed character to your string "Write success" when in fact you are telling the compiler to take your constant string and only stream from the 10th character. Remember a constant string here is just an array of characters and the single character '\n' is converted to the number 10.
You are also missing the result out of the streaming.
So your second to last line should read:
std::cout << "Write success: " << res << std::endl;

Related

getline truncating input in buffer overflow control example

So I'm coming up with a simple solution to control and notify the user if a buffer overflow is detected.
First, the input char array is set up using a size variable, and then the getline function takes in input up to that size.
const int charMax = 20;
const std::string account_number = "CharlieBrown42";
char user_input[charMax];
std::cout << "Enter a value: ";
std::cin.getline(user_input, charMax);
Then I check and see if there is anything left in the buffer -- if so, I let the user know that buffer overflow was attempted, but only the right amount of input was read.
if ((std::cin.rdbuf()->in_avail() - 2) > 0) {
std::cout << "Buffer overflow was attempted, but input was automatically trimmed" << std::endl;
}
std::cout << "You entered: " << user_input << std::endl;
std::cout << "Account Number = " << account_number << std::endl;
However, when tested, the printed final user_input is always only 19 characters. This is problematic because I am supposed to be able to take in up to 20 characters before buffer overflow occurs ( > charMax). getline() is always truncating one character more than I need it to.
Where am I going wrong?

A 'stack overflow' error returns upon any array size I enter above 36603. How can I make a string capable of capturing my entire .txt file?

I need to create a string capable of holding the entire book 'The Hunger Games' which comes out to around 100500 words. My code can capture samples of the txt, but anytime I exceed a string size of 36603(tested), I receive a 'stack overflow' error.
I can successfully capture anything below 36603 elements and can output them perfectly.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
int i;
char set[100];
string fullFile[100000]; // this will not execute if set to over 36603
ifstream myfile("HungerGames.txt");
if (myfile.is_open())
{
// saves 'i limiter' words from the .txt to fullFile
for (i = 0; i < 100000; i++) {
//each word is saparated by a space
myfile.getline(set, 100, ' ');
fullFile[i] = set;
}
myfile.close();
}
else cout << "Unable to open file";
//prints 'i limiter' words to window
for (i = 0; i < 100000; ++i) {
cout << fullFile[i] << ' ';
}
What is causing the 'stack overflow' and how can I successfully capture the txt? I will later be doing a word counter and word frequency counter, so I need it in "word per element" form.
There's a limit on how much stack is used in a function; Use std::vector instead.
More here and here. The default in Visual studio is 1MB (more info here) and you can change it with /F, but this is a bad idea generally.
My system is Lubuntu 18.04, with g++ 7.3. The following snippet shows some "implementation details" of my system, and how to report them on yours. It would help you to understand what your system provides ...
void foo1()
{
int i; // Lubuntu
cout << "\n sizeof(i) " << sizeof(i) << endl; // 4 bytes
char c1[100];
cout << "\n sizeof(c1) " << sizeof(c1) << endl; // 100 bytes
string s1; // empty string
cout << "\n s1.size() " << s1.size() // 0 bytes
<< " sizeof(s1) " << sizeof(s1) << endl; // 32 bytes
s1 = "1234567890"; // now has 10 chars
cout << "\n s1.size() " << s1.size() // 10 bytes
<< " sizeof(s1) " << sizeof(s1) << endl; // 32 bytes
string fullFile[100000]; // this is an array of 100,000 strings
cout << "\n sizeof(fullFile) " // total is vvvvvvvvv
<< sops.digiComma(sizeof(fullFile)) << endl; // 3,200,000 bytes
uint64_t totalChars = 0;
for( auto ff : fullFile ) totalChars += ff.size();
cout << "\n total chars in all strings " << totalChars << endl;
}
What is causing the 'stack overflow' and how can I successfully
capture the txt?
The fullFile array is an unfortunate choice ... because each std::string, even when empty, consumes 32 bytes of automatic memory (~stack), for a total of 3,200,000 bytes, and this is with no data in the strings! This will stack overflow your system when the stack is smaller than the automatic var space.
On Lubuntu the default automatic-memory size (lately) is 10 M Bytes, so not a problem for me. But you will have to check on what your version of your target os defaults to. I think Windows defaults down near 1 M Byte. (Sorry, I don't know how to check Windows automatic-memory size.)
How can I make a string capable of capturing my entire .txt file.
The answer is -- you don't need to make your own. (unless you have some unstated requirement)
Also, you really should look at en.cppreference.com/w/cpp/string/basic_string/append".
In my 1st snippet above, you should take notice that the sizeof(string) reports 32 bytes, regardless of how many chars are in it.
Think on that a while ... if you put 1000 chars into a string, where do they go? The objects stays at 32 bytes! You might guess or read that the string object handles memory management on your behalf, and puts all characters into dynamic-memory (heap).
On my system, heap is about 4 G bytes. That's a lot more than stack.
In summary, every single std::string expands auto-magically, using heap, so if your text input will fit in heap, it will fit into '1 std::string'.
While browsing around in the cppreference, check out the 'string::reserve()' command.
Conclusion:
Any std::string you declare can auto-magically 'grow' to support your need, and will thus hold the entire text (if it will fit in memory).
Operationally, you simply get a line of text from the file, then append it to the single string, until the entire file is contained. You only need the one array, which std::string provides.
With this new idea ... I suggest you change fullFile from an array to a string.
string fullFile; // file will expand to handle append actions
// to the limit of available heap.
// open file ... check status
do {
myfile.getline(line); // fetch line of text up thru the line feed
// Note that getline does not put the \n into 'line'
// there are file state checks that should be done (perhaps here?)
// tbd - line += '\n';
// you may need the line feed in your fullFile string?
fullFile += line; // append the line
} while (!myfile.eof); // check for eof
// ... other file cleanup.
foo1() output on Lubuntu 18.04, g++ v7.3
sizeof(i) 4
sizeof(c1) 100
s1.size() 0 sizeof(s1) 32
s1.size() 10 sizeof(s1) 32
sizeof(fullFile) 3,200,000
total chars in all strings 0
Example slurp() :
string slurp(ifstream& sIn)
{
stringstream ss;
ss << sIn.rdbuf();
dtbAssert(!sIn.bad());
if(sIn.bad())
throw "\n DTB::slurp(sIn) 'ss << sIn.rdbuf()' is bad";
ss.clear(); // clear flags
return ss.str();
}

Need to convert char* to string or other type in order to run hash on it

I need to read in an mp3 file so that I can run the hash(). I do not need to parse the mp3 tag data out of this so I can just read the whole thing all together.
Currently I am using ifstream() to open the file in binary mode. I then get the size of the file, allocate enough space with a char* and read it all at once.
I know that when I run cout on this data I can only see "ID3 and some gibberish." I opened the mp3 file up in a hex editor and ID3 and the gibberish was what was at the beginning of the file. The next binary data I believe is being interpreted as end of line/string and does not print.
This is okay because I don't need to print it. I need to get the data in a format that I can run the Hash function on. Any ideas on a type I can convert it to that will not interpret the end of the file being a couple bytes in?
Here is code of what I have so far.
bool Sender::openSoundFile(){
streampos size;
soundSampleStream.open(soundFilePath.c_str(), ios::in|ios::binary|ios::ate);
if(!soundSampleStream.is_open()){
return false;
}
size = soundSampleStream.tellg();
cout << "Size of MP3: " << size << endl;
soundFileInMemory = new char [size];
soundSampleStream.seekg (0, ios::beg);
soundSampleStream.read(soundFileInMemory, size);
cout << "Error is: " << strerror(errno) << endl;
cout << "gcount: " << soundSampleStream.gcount() << endl;
soundSampleStream.close();
cout << soundFileInMemory << endl;
return true;
}
I get no error on reading the file and gcount() comes back with the correct numbers of bytes for the file.
Edit 1:
To add some more on this. The hash() seems to hash the char* and not the data being pointed at because the hash value changes on different program runs. This is why I need to convert to some other thing. I also don't think that a vector is supported by the c++11 hash().
std::string has a constructor that takes a char * and a size_t. See the fourth item in http://en.cppreference.com/w/cpp/string/basic_string/basic_string.
std::string file_contents(soundFileInMemory, size);
That will convert your char array to a string.

reading and writing to the same file c++

I have small app which at begin will read text file (with serialized objects) in which im storing some obejcts (im doing it by overloading << and >> operators). This text file has to be updated each time new object is created:
fstream m_haystackMapFile;
m_haystackMapfile.open(haystackMapFile, std::ios::binary | std::ios::in | std::ios::out);
first i do read:
WHaystackFile f;
m_haystackMapfile.seekg(0, std::ios::beg);
std::copy(std::istream_iterator<WHaystackFile>(m_haystackMapfile), std::istream_iterator<WHaystackFile>(), std::back_inserter(m_haystackFiles));
std::cout << "reading input file, no of files: " << m_haystackFiles.size() << std::endl;
for(std::vector<WHaystackFile>::iterator it = m_haystackFiles.begin(); it != m_haystackFiles.end(); ++it){
f = *it;
std::cout << "key: " << f.getKey() << " cookie: " << f.getCookie() << " path: " << f.getPath() << " size: " << f.getSize()<< std::endl;
}
then after creating new object I do write:
void WhaystackMap::addEntry(WHaystackFile &f){
std::cout << "adding entry to index file" << std::endl;
m_haystackMapfile.seekp(std::ios::end);
m_haystackMapfile << f;
std::cout << f;
}
unfortunatelly file in which I want to write is never updated and it always has size 0. Maybe im messing up something, but after googling i can't find answer how to using fstream I can read and write to same file...
any help is welcomed :)
regards
J.
It's very important to check success of I/O operations. For example, if seekp is unable to seek to the desired position, it will set the failbit, and then all subsequent writes will fail. Or, as #Christophe points out, if you read the file to the end, you will cause the eofbit to be set. Unless that bit is cleared, the next I/O operation (even seekp) will fail.
Even if the eofbit had been reset, the seek probably would fail because the call should have been m_haystackMapfile.seekp(0, std::ios::end);.
The problem is the wrong usage of seekp():
you use it with one single parameter ios::end in m_haystackMapfile.seekp(std::ios::end)
but single parameter only works for absolute positionning. So ios::end is converted into an integer and will locate you at an unexpected place (on my implementation it's 2).
you have to use m_haystackMapfile.seekp(0, std::ios::end) instead
There is another problem: the istream_iterator<>() that you use in your std::copy() will read the stream until it reaches its end. So the failbit and eofbit will be set.
Connsequently, no stream operation will succed until you clear the flags: m_haystackMapfile.clear();

unexpected behavior when read a character from istringstream

I have a question on the stream behavior, see the following example. What I was expecting is the ss_char and ss_int will be eof state, but just the ss_int will be eof state.
My question is, why isn't ss_char eof state?
Can't I use the operator>>, only the istringstream::get() function, but then why read the value successfully?
Output:
char value: a
int value: 42
ss_char eof: false // why false?
ss_int eof: true
Sorry for my poor English. I’m working on improving my English.
#include <iostream>
#include <sstream>
int main(int /*argc*/, char const * /*argv*/[])
{
char c;
int num;
std::istringstream ss_int("42");
std::istringstream ss_char("a");
if (ss_char >> c)
{
std::cout << "char value: " << c << std::endl;
}
else
{
std::cout << "cannot read char" << std::endl;
}
if (ss_int >> num)
{
std::cout << "int value: " << num << std::endl;
}
else
{
std::cout << "cannot read int" << std::endl;
}
std::cout << std::endl;
std::cout << "ss_char eof: " << std::boolalpha << ss_char.eof() << std::endl; // why false
std::cout << "ss_int eof: " << std::boolalpha << ss_int.eof() << std::endl;
return 0;
}
CppReference says: "This function only reports the stream state as set by the most recent I/O operation, it does not examine the associated data source. For example, if the most recent I/O was a get(), which returned the last byte of a file, eof() returns false. The next get() fails to read anything and sets the eofbit. Only then eof() returns true."
oefbit will turn true when a read operation attempts to read beyond end of file, but not when it reads exactly to the end of file without trying to go further. When you read the char, it knows it should read a single byte, so this read operation is ok, the read position advance 1 byte, goes to the end, but let say the the stream still haven't noticed that it is indeed the end, it will if you try to read something else. When you read an integer, it tries to read beyond 42 because the length of the integer is not clear, it could have been 42901, so it has to read until it sees an space, and end of line, or eventually the end of the file/stream if there's nothing else to read.
And the result of the operator >> is the stream itself. When it is converted to void* (or bool, depends on c++11 or previous) it works as !fail(), so it tells you if the read or write operation was ok, regardless of whether it reached the end of file (next read operation will fail if it is now at the end).
The EOF condition doesn't actually occur until you try to read past the end of the stream.
In the char case you read exactly one character, the only one available. You don't try to read past the end because there is no need to.
Extracting an int on the other hand attempts to consume as many digits as possible. It reads the 4 and the 2, and then it tries to read again to see if there is another digit to consume, it does attempt to read past the end in this case. It notices that the input came to an end and so finishes the conversion of 42.
when extracting chars, it will pull a single character at a time and skip white spaces on consecutive calls.
when extracting int, the parser attempts to pull as many characters out to form the number. this causes the integer extraction to hit the eof in your test case.