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;
}
}
}
}
}
}
Related
Write a function countMatches that searches the substring in the given string and returns how many times the substring appears in the string.
I've been stuck on this awhile now (6+ hours) and would really appreciate any help I can get. I would really like to understand this better.
int countMatches(string str, string comp)
{
int small = comp.length();
int large = str.length();
int count = 0;
// If string is empty
if (small == 0 || large == 0) {
return -1;
}
// Increment i over string length
for (int i = 0; i < small; i++) {
// Output substring stored in string
for (int j = 0; j < large; j++) {
if (comp.substr(i, small) == str.substr(j, large)) {
count++;
}
}
}
cout << count << endl;
return count;
}
When I call this function from main, with countMatches("Hello", "Hello"); I get the output of 5. Which is completely wrong as it should return 1. I just want to know what I'm doing wrong here so I don't repeat the mistake and actually understand what I am doing.
I figured it out. I did not need a nested for loop because I was only comparing the secondary string to that of the string. It also removed the need to take the substring of the first string. SOOO... For those interested, it should have looked like this:
int countMatches(string str, string comp)
{
int small = comp.length();
int large = str.length();
int count = 0;
// If string is empty
if (small == 0 || large == 0) {
return -1;
}
// Increment i over string length
for (int i = 0; i < large; i++) {
// Output substring stored in string
if (comp == str.substr(i, small)) {
count++;
}
}
cout << count << endl;
return count;
}
The usual approach is to search in place:
std::string::size_type pos = 0;
int count = 0;
for (;;) {
pos = large.find(small, pos);
if (pos == std::string::npos)
break;
++count;
++pos;
}
That can be tweaked if you're not concerned about overlapping matches (i.e., looking for all occurrences of "ll" in the string "llll", the answer could be 3, which the above algorithm will give, or it could be 2, if you don't allow the next match to overlap the first. To do that, just change ++pos to pos += small.size() to resume the search after the entire preceding match.
The problem with your function is that you are checking that:
Hello is substring of Hello
ello is substring of ello
llo is substring of llo
...
of course this matches 5 times in this case.
What you really need is:
For each position i of str
check if the substring of str starting at i and of length = comp.size() is exactly comp.
The following code should do exactly that:
size_t countMatches(const string& str, const string& comp)
{
size_t count = 0;
for (int j = 0; j < str.size()-comp.size()+1; j++)
if (comp == str.substr(j, comp.size()))
count++;
return count;
}
I managed to get my homework to work but It shouldn't work because i have not finished it. I don't know why it does. I need help.
#include<iostream>
using namespace std;
char* trim(char* str) {
const int lenStr = strlen(str);
int characters = 0;
bool trimmableFront = false;
int firstChar;
//check if trimmableFront + location of first char
for (int i = 0; i < lenStr; i++) {
if (*(str + i) != ' ') {
if (characters == 0)
firstChar = i;
characters++;
}
if (characters == 0) {
trimmableFront = true;
}
}
//trim Front //THIS PART SHOULD BEHAVE DIFFERENTLY
if (trimmableFront) {
for (int i = 0; i < lenStr; i++) {
if((firstChar + i <= lenStr))
*(str + i) = *(str + firstChar + i);
}
}
return str;
}
int main() {
char str[] = " why does it work?";
trim(str);
cout<< str <<endl;
return 0;
}
At the end of trim(*char) function, trimmed string should have still leftovers from previous locations.
For some reason it is perfectly trimmed and works as intended printing "why does it work?" but it should print something like "why does it workt work?"
The reason why it works is because as you trim the string by shifting each character you also shift the terminating null character '\0'. As you probably know c-strings are array of characters terminated by '\0', so as you print str with cout all characters are printed until the null value is reached: that is way the leftovers are not printed.
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;
I have a C++ function that splits a char array into multiple char arrays when it encounters a delimiter. For some reason, when saving the third split array the program just crashes and sometimes returns an std::bad_alloc exception.
char ** explode(const char * arr, const char delim) {
int start, end, curr=0, count=1;
char ** strings;
//Iegūst explodēto stringu skaitu
for (int i = 0; arr[i] != 0; i++) {
if (arr[i] == delim && i != 0 && arr[i+1] != 0 && arr[i+1] != delim ) { //Nav pirmais, nav pēdējais, nav pa labi vēlviens delimiters
count++;
}
}
strings = new char*[count];
start = 0;
for (int i = 0; arr[i] != 0; i++) {
if (arr[i] == delim || arr[i+1] == 0) {
if (arr[i] == delim) {
end = i;
} else {
end = i+1;
}
if (end-start < 1) {
start++;
} else {
copystring(arr,strings[curr++],start,end-start);
start = i+1;
}
}
}
for (int i = 0; i < count; i++) {
cout << strings[i] << endl;
}
return strings;
}
//Pārkopē daļu no pirmā char masīva uz otru, no START pozīcijas, līdz GARUMS garumā
void copystring(const char * from, char *& to, const int start, const int garums) {
int curr=0;
if (garums < 1 || start > charlen(from)) {
return;
}
to = new char[garums];
for (int i = start; i < start+garums && from[i] != 0; i++) {
to[curr++] = from[i];
}
to[curr] = 0;
}
It's hard to tell because it doesn't really tell me at which line everything goes wrong, but I think it happens at
to = new char[garums];
I've tried debugging this line within CodeBlocks, but for some reason when using breakpoints and tracking the variables the applications works fine and executes correctly. It only crashes when running it normally, without debugging...
Also note, that I can't use strings or pretty much any library except fstream and iostream.
EDIT: I tried changing the new char[garums] part to new char[100] and it magically started working. The problem is that I then changed it to new char[10] in which case everything still worked. I even outputted the saved text to the console and it saved everything properly. How could it have saved big words in a char array that is 10 character long (the words I'm testing are longer than 10 characters)? When I changed it to new char[1] however it started crashing again, but again only after the 3rd loop iteration. So it somehow saved the first 2 words in a 1 character long array?
EDIT2: And now it magically started working even with new char[garums]. Something is really wrong here, anyone have any ideas?
The bug you refer to in your question likely crops up when trying to use the pointer
to pointer being returned from the explode function.
Some pointers ; If you have to write C code, don't use a mishmash of C/C++,
Use the library functions rather than re-inventing the wheel (strncpy in copystring)
Your word count was off because you didn't take into account the word between
the last delimiter and EOL
Below are some minor changes to your code as a complete example :
#include <stdio.h>
#include <strings.h>
void copystring(const char *from, char **to, const int numchars)
{
if (numchars > 0) {
*to = new char[numchars];
strncpy(*to, from, numchars) ;
(*to)[numchars] = '\0' ;
}
}
char **explode(const char * buffer, const char delim)
{
int count = 0 ;
if (strlen(buffer) > 0) {
int inword = 0 ;
int idx = 0 ;
do {
if (buffer[idx] == delim || buffer[idx] == '\0') {
if (inword == 1) {
count++ ;
inword = 0 ;
}
} else {
inword = 1 ;
}
} while (buffer[idx++] != 0) ;
}
int start = 0;
int end = 0 ;
int curr = 0 ;
int idx = 0 ;
char **values = new char*[count+1];
do {
if (buffer[idx] == delim || buffer[idx] == '\0') {
end = idx;
if (end-start > 0) {
copystring(&buffer[start], &values[curr++], end - start) ;
}
start = ++end ;
}
} while (buffer[idx++] != 0) ;
values[curr] = NULL ;
for (int idx = 0; idx < count; idx++) {
fprintf(stdout, "'%s'\n", values[idx]) ;
}
return values;
}
int main(int argc, char *argv[])
{
char inputstr[] = "The, quick, brown, fox, jumped, over,,, ,,, ,,,,, ,,,, the, lazy, dog's, back" ;
char **values = explode(inputstr, ',') ;
while (*values != NULL) {
fprintf(stdout, "%s\n" , *values) ;
*values++ ;
}
return (0) ;
}
Since I don't know what input data you have I will have to guess:
Here you allocate your pointer array but please note that all the pointers are uninitialized.
strings = new char*[count]
then when you parse the code you use a variable curr which you let run freely so it is not certain that all strings[] have been set to some value or whether curr lands on a number larger than count.
If I were you I would put in a check to make sure that:
a) curr does not exceed count
b) that if curr lands on a value less than count, set the rest of the pointers to nullptr
This has probably to do with to being of type char*& instead of type char*.
On the other hand, I never programmed C++ like this (are you sure that this is not C?). Using explicit memory management (like ´new´) is as good as playing playing russian roulette.
Here is a more standard C++ way of doing this:
#include <vector>
#include <string>
#include <iostream>
std::vector<std::string> splitString(std::string& str, char c) {
std::vector<std::string> substrings;
while(true) {
unsigned pos = str.find(c);
substrings.push_back(str.substr(0,pos));
if(pos == std::string::npos) break;
str = str.substr(pos+1);
}
return substrings;
}
int main()
{
char c = '*';
std::string str = "Some*string*that we need to split*properly*";
std::vector<std::string> result = splitString(str,c);
for(unsigned i = 0; i < result.size(); ++i) {
std::cout << i << ": " << result[i] << "\n";
}
}
Output:
0: Some
1: string
2: that we need to split
3: properly
4:
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[].