How to copy every 16 bytes of data from a string? - c++

I have to copy data into sets of 16 bytes. How do i do it with an easy way?
I've come up with the below algorithm but how do i know if the null terminator has been added? thanks! :)
std::string input
//get message to send to client
std::cout << "Enter message to send (type /q to quit) : ";
getline(std::cin, input);
input += '\n';
const char *data = input.c_str();
len = strlen(data)+1;
int max_len =17;
//split msg into 16 bytes
for(int i = 0; i < len ; i+=max_len)
{
char tempStr[max_len];
//get next 16 bytes of msg and store
for(int j = 0; j < max_len ; j++)
{
tempStr[j] = data[j+i];
}//end of for loop
//Do some stuff to tempStr
}

In your code, the string terminator is not added. You also skip one character between the copies (since you have max_len as 17 while you only copy 16characters).
I would propose a solution using the standard library instead:
std::string::const_iterator pos = input.begin();
while (pos < input.end())
{
// Create a temporary string containing 17 "null" characters
char tmp[17] = {'\0' };
// Make sure we co no copy beyond the end
std::string::const_iterator end =
(pos + 16 < input.end() ? pos + 16 : input.end());
// Do the actual copying
std::copy(pos, end, tmp);
// Advance position
pos += 16;
// Use the string in 'tmp', it is properly terminated
}

const char* data = input.c_str();
int len = input.size(); // don't add 1
for (int i=0; i<len; i+=16)
{
char tempStr[17];
tempStr[16] = 0;
strncpy(tempStr, data + i, 16);
// Do some stuff to tempStr
}
Depending upon what you actually do with tempStr, there might be a solution that involves no copying at all.
for (int i=0; i<len; i+=16)
{
llvm::StringRef sref(data + i, data + std::min(i+16,len));
// use sref
}
llvm::StringRef

Related

the program should display the last 5 lines of the file, but it does not work with large files

I wrote a program that should print the last 5 lines of a file, but the teacher created a file with a line of 4 GB, and the program broke. How to rewrite a program so that it can work with very large files
a possible solution is to read the file character by character, but I don’t know how to do it
here is the c ++ program code
#include <iostream>
#include <fstream>
#include <string>
using std::ifstream;
using std::cout;
using std::string;
using std::getline;
int main(int argc, char * argv[], char * env[]) {
setlocale(LC_ALL, "");
int i;
string line;
if (argc == 3) {
string filename = argv[1];
ifstream myfile(filename);
string n = argv[2];
int nn = atoi(n.c_str());
string line, buffer[nn];
const size_t size = sizeof buffer / sizeof * buffer;
size_t i = 0;
while (getline(myfile, line)) {
buffer[i] = line;
if (++i >= size) {
i = 0;
}
}
for (size_t j = 0; j < size; ++j) {
cout << buffer[i] << "\n";
if (++i >= size) {
i = 0;
}
}
//return 0;
}
}
The problem must be with big lines in that 4GB file. Your solution buffers (and later drops) every line and at least one of the lines is probably too long to be buffered in the machine you're running, making your program crash.
You should read the file starting from the end counting the number of newlines and stop and output the rest of if when you reach the count of nn + 1. Buffering the last nn lines is not a good option when you need to handle big lines.
Here a snippet of a solution that could help you:
array<char, 64 * 1024> buffer; // 64kb of buffer
size_t nn = atoi(n.c_str());
myfile.seekg(0, ios_base::end);
unsigned int nlcount = 0;
size_t length = myfile.tellg();
size_t oldpos = length;
while (myfile.tellg() > 0) {
size_t newpos = oldpos - min(oldpos, buffer.size());
myfile.seekg(newpos);
size_t rdsize = oldpos - newpos;
myfile.read(buffer.data(), rdsize);
if (!myfile) {
cerr << "failed while looking for newlines\n";
return 1;
}
auto rit = buffer.rbegin() + (buffer.size() - rdsize);
while (rit != buffer.rend() && nlcount <= nn) {
if (*rit == '\n') {
++nlcount;
}
++rit;
}
if (nlcount > nn) {
myfile.seekg(newpos + (buffer.rend() - rit) + 1);
break;
}
oldpos = newpos;
}
This will point the input stream to the exact position where you just need to output the rest of it if nlcount is equal to nn + 1. I recommend you to output it not using buffered lines, but using a fixed sized buffer:
while (myfile.peek() != EOF) {
myfile.read(buffer.data(), buffer.size());
cout.write(buffer.data(), myfile.gcount());
}
Don't use getline() or you will still end up buffering lines and crash when handling long ones.
To remove buffer dependency one way is to read the file from the end backward to reach the number of lines you want. 5 is hard-coded here but you can pass it as a parameter.
std::ifstream fileReader("test.txt", std::ios_base::ate );
std::string currentLine;
long length;
int lines;
char c = '\0';
if( fileReader )
{
length = fileReader.tellg();
for(long i = length-2; i > 0; i-- )
{
fileReader.seekg(i);
c = fileReader.get();
if( c == '\r' || c == '\n' )
{
lines++;
if (lines == 5)
break;
}
}
while(fileReader)
{
std::getline(fileReader, currentLine);
std::cout << currentLine << std::endl;
}
}

Insert symbol into string C++

I need to insert symbol '+' into string after its each five symbol.
st - the member of class String of type string
int i = 1;
int original_size = st.size;
int count = 0;
int j;
for (j = 0; j < st.size; j++)
{
if (i % 5)
count++;
}
while (st.size < original_size + count)
{
if (i % 5)
{
st.insert(i + 1, 1, '+');
st.size++;
}
i++;
}
return st;
I got an error in this part of code. I think it is connected with conditions of of the while-cycle. Can you help me please how to do this right?
If I've understood you correctly then you want to insert a '+' character every 5 chars in the original string. One way to do this would be to create a temporary string and then reassign the original string:
std::string st("A test string with some chars");
std::string temp;
for (int i = 1; i <= st.size(); ++i)
{
temp += st[i - 1];
if (i % 5 == 0)
{
temp += '+';
}
}
st = temp;
You'll notice I've started the loop at 1, this is to avoid the '+' being inserted on the first iteration (0%5==0).
#AlexB's answer shows how to generate a new string with the resulting text.
That said, if your problem is to perform in-place insertions your code should look similar to this:
std::string st{ "abcdefghijk" };
for(auto i = 4; i != st.size(); i += 5)
st.insert(i+1, 1, '+'); // insert 1 character = '+' at position i
assert(st == "abcde+fghij+k");
std::string InsertEveryNSymbols(const std::string & st, size_t n, char c)
{
const size_t size(st.size());
std::string result;
result.reserve(size + size / n);
for (size_t i(0); i != size; ++i)
{
result.push_back(st[i]);
if (i % n == n - 1)
result.push_back(c);
}
return result;
}
You don't need a loop to calculate the length of the resulting string. It's going to be simply size + size / 5. And doing multiple inserts makes it a quadratic-complexity algorithm when you can just as easily keep it linear.
Nothing no one else has done, but eliminates the string resizing and the modulus and takes advantage of a few new and fun language features.
std::string temp(st.length() + st.length()/5, '\0');
// preallocate string to eliminate need for resizing.
auto loc = temp.begin(); // iterator for temp string
size_t count = 0;
for (char ch: st) // iterate through source string
{
*loc++ = ch;
if (--count == 0) // decrement and test for zero much faster than
// modulus and test for zero
{
*loc++ = '+';
count = 5; // even with this assignment
}
}
st = temp;

Strings over 15 characters get turned to ε■ε■ε■ε■ε■ε■ε■ε■ε

I have been implementing a factory for a component based game engine recently. I am deserializing objects by reading in from a file what component they need and what to initialize them with. It works except for when I try to read in a property longer than 15 characters. At 15 characters, it reads it in perfectly, anything longer and I get "ε■ε■ε■ε■ε■ε■ε■ε■ε" as output.
I am using std::string to store these lines of text.
Example:
JunkComponent2 test "1234567890123456" test2 "123456789012345"
With this the value of test becomes garbage, while test2 stays perfectly intact.
Any idea's what might be going on?
char line[1024];
while (file.getline(line, 1024))
{
std::vector<std::string> words;
std::string word;
int j = 0;
for (unsigned i = 0; line[i] != '\0' && i < 1024; ++i)
{
if (line[i] == ' ' && j > 0 && line[i - 1] != '\\')
{
words.push_back(word);
j = 0;
word = "";
}
else
{
++j;
word += line[i];
}
}
words.push_back(word);
// std::cout << (*Parts)["JunkComponent"]->GetName() << std::endl;
Component* c = (*Parts)[words[0]]->clone(words);
object->AddComponent(words[0], c);
for (std::list<Member*>::iterator it = members.begin(); it != members.end(); ++it)
{
for (unsigned i = 0; i < words.size(); ++i)
{
if ((*it)->GetName() == words[i])
{
if (words[i + 1][0] == '\"')
{
std::vector<char> chars;
chars.push_back('\"');
chars.push_back('\\');
for (unsigned int n = 0; n < chars.size(); ++n)\
{
words[i + 1].erase(std::remove(words[i + 1].begin(), words[i + 1].end(), chars[n]), words[i + 1].end());
}
Container((*it)->GetMeta(), GET_MEMBER(data.GetData(), (*it)->GetOffset()), (*it)->GetName()).SetValue<std::string>(words[i + 1]);
}
else
{
Container((*it)->GetMeta(), GET_MEMBER(data.GetData(), (*it)->GetOffset()), (*it)->GetName()).SetValue<int>(std::stoi(words[i + i]));
}
++i;
break;
}
}
}
}
GET_MEMBER Macro expands to:
#define GET_MEMBER(P, OFFSET) ((void *)(((char *)(P)) + (OFFSET)))
SetValue Function: (data is a void*)
template <typename T>
void SetValue(T data_)
{
memcpy(data, &data_, sizeof(T));
}
I'll take a stab having just eyed your code. GET_MEMBER is really nasty and I think that's where your problem is. It seems to rely on std::string being convertible to char*, which it is not. Why does your code work with strings shorter than 15? Well that's more than likely because std::string on most popular implementations actually contains a special case for strings where it keeps an internal buffer of length 16 ( last element \0 ) to avoid dynamic memory allocation. When the string is larger than 15 this buffer is uninitialized because it isn't used. The correct way to access the string is by using operator[].

C++ Letters -> Numbers

This is my first time posting a question to Stack Overflow. I am new at programming so please excuse me if I say things strange or wrong. In the file below; it reads the directory and saves it to a variable nAddress. It then removes the file extension; breaks up the file into 700 lines each rebuilds the extension; and lastly, increments the filename by 1 letter IE: testA, testB, testC, testD, etc.
Reworded:
Current Output:
Test is 1400 lines so it outputs
TestA
TestB
IT NEEDS TO BE:
Test1
Test2
Could you point me in the right direction? Thanks!
string fAddress = argv[1];
if (argc > 2)
{
for (int i = 2; i < argc; i++)
{
string temp = argv[i];
fAddress = fAddress + " " + temp;
}
}
cout << fAddress << "\n" <<endl;
// Convert to a char*
const size_t newsize = 500;
char nstring[newsize];
strcpy_s(nstring, fAddress.c_str());
strcat_s(nstring, "");
// Convert to a wchar_t*
size_t origsize = strlen(fAddress.c_str()) + 1;
size_t convertedChars = 0;
wchar_t wcstring[newsize];
mbstowcs_s(&convertedChars, wcstring, origsize, fAddress.c_str(), _TRUNCATE);
wcscat_s(wcstring, L"");
ifstream inFile;
inFile.open (wcstring);
int index = 0;
string parts[100];
string text;
for (int i = 0; i < 100; i++)
{
parts[i] = "";
}
// get info until ; is found in each line and add it to the array of char*
while ( !inFile.eof( ) )
{
getline(inFile, text, (char)1);
if ( !inFile )
{
if (inFile.eof( ) )
break;
else
{
cout << "File error...\n";
break;
system("PAUSE");
}
}
parts[index] += text;
index++;
}
inFile.close();
int n = fAddress.length(); // Get the total size of the file name.
string nAddress = "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++";
cout<<"Removing previous file extension...\n";
n = n - 4; //Remove the extension from the output file
cout<<"Removed previous file extension successfully...\n\n";
cout<< "Building file location and name....\n";
for (int i = 0; i < n; i++)
{
nAddress[i] = nstring[i]; //nstring hold the name
}
cout<< "Built successfully....\n\n";
//Now nAddress is equal to the location and name of the file....
nAddress[n] = '0' ;//'A';
cout<<nAddress[n];
// nAddress[n+1] = 1+48;
//system("cls");
cout<< "Building file extension...\n"<< endl;
for (int i = n; i < n+4; i++) // n is whatever the length of the string is. Add 4 chars onto the n.
{
nAddress[i+1] = nstring[i];
fileextension = fileextension + nstring[i]; //This saves off the full file extension for later use. :)
//cout <<nAddress; This seems to build the extension of the file... IE .T, .TA, .TAP
}
cout<< "File extension built successfully...\n"<< endl;
nAddress[n+5] = '\0';
//cout<< nAddress;
string files[10];
//This is the part that searches through the file and splits it up I believe.
for (int i = 0; i < index-2; i++)
{
files[i] = parts[0] + parts[i+1] + parts[index-1];
//cout<< files[i]; //This line will output the entire file in the CMD window
}
//system("cls");
// The function below is where the names are dished out
nAddress[n-20];
int counter = 0;
int lastnum;
for (int i = 0; i < index-2; i++)
{
//string myval;
//ostringstream convert;
//counter++;
//convert << counter ;
nAddress[n] = i + 65; //this is the line that gives the letters... it comes in with an A as the first file FYI
//nAddress = nAddress + convert.str();
//cout<<convert.str();
//cout<<counter;
//myval = nAddress[n];
//cout<<myval;
cout<<"Outputting sub-files...\n" <<endl;
cout<<nAddress<< "\n" << endl;
size_t origsize = strlen(nAddress.c_str()) + 1;
size_t convertedChars = 0;
wchar_t wcstrings[newsize];
mbstowcs_s(&convertedChars, wcstrings, origsize, nAddress.c_str(), _TRUNCATE);
wcscat_s(wcstrings, L"");
ofstream outFile (wcstrings);
outFile << files[i];
}
Use s.th. like this:
std::string getPartFilename(int partNumber)
{
std::ostringstream oss;
oss << "Test" << partNumber;
return oss.str();
}
UPDATE
To clarify my point: Refactor your code to remove all those pesky c string operations (strcpy_s() , strcat_s(), etc.) for building the file names, and use a simple straightforward C++ standard mechanism to format the strings as you need them.
okay, so if
nAddress[n] = i + 65;
is truly where the incremented letter of the file gets set, than here's what I'd do.
since you're using std:string,
// make your address just "test"
nAddress[n] = '\0';
// cast `i` to a string and concatinate
nAddress += to_string(i);
http://www.cplusplus.com/reference/string/to_string/
http://www.cplusplus.com/reference/string/string/operator+=/
If you weren't using std:string you'd approach it like this
// make your address just "test"
nAddress[n] = '\0';
// make a character array that contains the character representation of `i`
char buffer[50];
sprintf("%d", i);
// concatinate
strcat(nAddress, buffer);
or, you can merely do
sprintf(&nAddress[n], "%d", i);
as indiv mentioned
To change the letter to a number (if I understand the code correct),
nAddress[n] = i + 65;
should become
nAddress[n] = i + '0';

remove commas from string

I created a program in C++ that remove commas (,) from a given integer. i.e. 2,00,00 would return 20000. I am not using any new space. Here is the program I created:
void removeCommas(string& str1, int len)
{
int j = 0;
for (int i = 0; i < len; i++)
{
if (str1[i] == ',')
{
continue;
}
else
{
str1[j] = str1[i];
j++;
}
}
str1[j] = '\0';
}
void main()
{
string str1;
getline(cin, str1);
int i = str1.length();
removeCommas(str1, i);
cout << "the new string " << str1 << endl;
}
Here is the result I get:
Input : 2,000,00
String length =8
Output = 200000 0
Length = 8
My question is that why does it show the length has 8 in output and shows the rest of string when I did put a null character. It should show output as 200000 and length has 6.
Let the standard library do the work for you:
#include <algorithm>
str1.erase(std::remove(str1.begin(), str1.end(), ','), str1.end());
If you don't want to modify the original string, that's easy too:
std::string str2(str1.size(), '0');
str2.erase(std::remove_copy(str1.begin(), str1.end(), str2.begin(), ','), str2.end());
You need to do a resize instead at the end.
Contrary to popular belief an std::string CAN contain binary data including 0s. An std::string 's .size() is not related to the string containing a NULL termination.
std::string s("\0\0", 2);
assert(s.size() == 2);
The answer is probably that std::strings aren't NUL-terminated. Instead of setting the end+1'th character to '\0', you should use str.resize(new_length);.
Edit: Also consider that, if your source string has no commas in it, then your '\0' will be written one past the end of the string (which will probably just happen to work, but is incorrect).
The std::srting does not terminate with \0, you are mixing this with char* in C. So you should use resize.
The solution has already been posted by Fred L.
In a "procedural fashion" (without "algorithm")
your program would look like:
void removeStuff(string& str, char character)
{
size_t pos;
while( (pos=str.find(character)) != string::npos )
str.erase(pos, 1);
}
void main()
{
string str1;
getline(cin, str1);
removeStuff(str1, ',');
cout<<"the new string "<<str1<<endl;
}
then.
Regards
rbo
EDIT / Addendum:
In order to adress some efficiency concerns of readers,
I tried to come up with the fastest solution possible.
Of course, this should kick in on string sizes over
about 10^5 characters with some characters to-be-removed
included:
void fastRemoveStuff(string& str, char character)
{
size_t len = str.length();
char *t, *buffer = new char[len];
const char *p, *q;
t = buffer, p = q = str.data();
while( p=(const char*)memchr(q, character, len-(p-q)) ) {
memcpy(t, q, p-q);
t += p-q, q = p+1;
}
if( q-str.data() != len ) {
size_t tail = len - (q-str.data());
memcpy(t, q, tail);
t += tail;
}
str.assign(buffer, t-buffer);
delete [] buffer;
}
void main()
{
string str1 = "56,4,44,55,5,55"; // should be large, 10^6 is good
// getline(cin, str1);
cout<<"the old string " << str1 << endl;
fastRemoveStuff(str1, ',');
cout<<"the new string " << str1 << endl;
}
My own procedural version:
#include <string>
#include <cassert>
using namespace std;
string Remove( const string & s, char c ) {
string r;
r.reserve( s.size() );
for ( unsigned int i = 0; i < s.size(); i++ ) {
if ( s[i] != c ) {
r += s[i];
}
}
return r;
}
int main() {
assert( Remove( "Foo,Bar,Zod", ',' ) == "FooBarZod" );
}
Here is the program:
void main()
{
int i ;
char n[20] ;
clrscr() ;
printf("Enter a number. ") ;
gets(n) ;
printf("Number without comma is:") ;
for(i=0 ; n[i]!='\0' ; i++)
if(n[i] != ',')
putchar(n[i]) ;
getch();
}
For detailed description you can refer this blog: http://tutorialsschool.com/c-programming/c-programs/remove-comma-from-string.php
The same has been discussed in this post: How to remove commas from a string in C
Well, if youre planing to read from a file using c++. I found a method, while I dont think thats the best method though, but after I came to these forums to search for help before, I think its time to contribute with my effort aswell.
Look, here is the catch, what I'm going to present you is part of the source code of the map editor Im building on right now, that map editor obviously has the purpose to create maps for a 2D RPG game, the same style as the classic Pokemon games for example. But this code was more towards the development of the world map editor.
`int strStartPos = 0;
int strSize = 0;
int arrayPointInfoDepth = 0;
for (int x = 0; x < (m_wMapWidth / (TileSize / 2)); x++) {
for (int y = 0; y < (m_wMapHeight / (TileSize / 2)); y++) {
if (ss >> str) {
for (int strIterator = 0; strIterator < str.length(); strIterator++) {
if (str[strIterator] == ',') {`
Here we need to define the size of the string we want to extract after the previous comma and before the next comma
`strSize = strIterator - strStartPos;`
And here, we do the actual transformation, we give to the vector that is a 3D vector btw the string we want to extract at that moment
`m_wMapPointInfo[x][y][arrayPointInfoDepth] = str.substr(strStartPos, strSize);`
And here, we just define that starting position for the next small piece of the string we want to extract, so the +1 means that after the comma we just passed
strStartPos = strIterator + 1;
Here, well since my vector has only 6 postions that is defined by WorldMapPointInfos we need to increment the third dimension of the array and finally do a check point where if the info has arrived the number 6 then break the loop
arrayPointInfoDepth++;
if (arrayPointInfoDepth == WorldMapPointInfos) {
strStartPos = 0;
arrayPointInfoDepth = 0;
break;
}
}
}
}
}
}
Either way on my code, think abt that the vector is just a string, thats all you need to know, hope this helps though :/
Full view:
int strStartPos = 0;
int strSize = 0;
int arrayPointInfoDepth = 0;
for (int x = 0; x < (m_wMapWidth / (TileSize / 2)); x++) {
for (int y = 0; y < (m_wMapHeight / (TileSize / 2)); y++) {
if (ss >> str) {
for (int strIterator = 0; strIterator < str.length(); strIterator++) {
if (str[strIterator] == ',') {
strSize = strIterator - strStartPos;
m_wMapPointInfo[x][y][arrayPointInfoDepth] = str.substr(strStartPos, strSize);
strStartPos = strIterator + 1;
arrayPointInfoDepth++;
if (arrayPointInfoDepth == WorldMapPointInfos) {
strStartPos = 0;
arrayPointInfoDepth = 0;
break;
}
}
}
}
}
}