I am trying to delete characters that aren't numbers nor letters from a string by such a stupid method since I failed in getting other methods ( I am a real beginner "just trying ")
I know that this way isn't the right one but my question is what the problem with it what is the error since it doesn't work :S
string g = "9-=p98u;iu8y76";
string y;
int t = 0;
for (int i = 0; i < g.length(); i++)
{
if (isdigit(g[i]) || isalpha(g[i]))
{
y[t++] = g[i];
}
else
continue;
}
g = y;
cout << g;
The problem is that the size of y is 0, it's empty. Accessing its elements (using y[t++]) therefore reaches "after" the string—it's buffer overflow, and Undefined Behaviour.
You need to extend y. To do this with minimal changes to your code, you'd do this:
string g = "9-=p98u;iu8y76";
string y;
for (int i = 0; i < g.length(); i++)
{
if (isdigit(g[i]) || isalpha(g[i]))
{
y.push_back(g[i]);
}
else
continue;
}
g = y;
cout << g;
Of course, there are other ways to do that. Using standard algorithms and the erase-remove idiom would be more idiomatic C++. The entire code can be replaced with this:
auto shouldBeRemoved = [](char c) { !(isdigit(c) || isalpha(c)) };
g.erase(std::remove_if(g.begin(), g.end(), shouldBeRemoved), g.end());
cout << g;
std::remove_if works by reorganising the range so that all elements which match the predicate (i.e. those which should be removed) are moved after all elements which are to remain. The member function erase then erases all of those which were moved to the back.
This is reasonably expressed by the standard library. Something like
auto digit_or_alpha = [](char c){ return isdigit(c) || isalpha(c); };
std::copy_if(g.begin(), g.end(), std::back_inserter(y), digit_or_alpha );
Should work. back_inserter is in <iterator>. Angew provides the reason why yours doesn't work.
The problem is the way you are trying to extend the string y. Indexing can be applied only in the domain of the string (i.e. you cannot index beyond the length of the string)
change y[t++] = g[i] to y += g[i]
Additionally, i would like to mention that you don't need the else branch. When execution reaches the end of loop scope, it will "automatically" continue, it isn't needed to be expressed explicitly.
PS: It's classic C++, not C++11, I would accept Captain Giraffe's answer
The general approach for such tasks is to use member function erase along with standard algorithm std::remove_if declared in header <algorithm>
For example
#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
int main()
{
std::string s = "9-=p98u;iu8y76";
std::cout << s << std::endl;
s.erase( std::remove_if( s.begin(), s.end(),
[]( char c )
{
return !std::isalnum( ( unsigned char )c );
} ),
s.end() );
std::cout << s << std::endl;
return 0;
}
The program output is
9-=p98u;iu8y76
9p98uiu8y76
As for your code then you are trying to use the subscript operator
y[t++] = g[i];
for an empty string
string y;
Take into acoount that instead of two functions std::isalpha and std::isdigit you can use one function std::isalnum as shown in my demonstrative program.
If you want to write loops yourself then the program can look like
#include <iostream>
#include <string>
#include <cctype>
int main()
{
std::string s = "9-=p98u;iu8y76";
std::cout << s << std::endl;
std::string::size_type i = 0;
while ( i < s.length() && std::isalnum( ( unsigned char )s[i] ) ) ++i;
std::string::size_type j = i;
while ( i++ < s.length() )
{
if ( std::isalnum( ( unsigned char )s[i] ) ) s[j++] = s[i];
}
s.erase( j );
std::cout << s << std::endl;
return 0;
}
The program output is the same as above
9-=p98u;iu8y76
9p98uiu8y76
There is no need to use an additional string to do this operation.
Related
To find all sequences of fixed length which contain only 0 and 1 I use this code:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
void print_array(vector<string> arr) {
cout << '[';
int n = arr.size();
for (size_t i = 0; i < n; i++) {
cout << arr[i];
if (i < (n - 1)) {
cout << ", ";
}
}
cout << ']' << endl;
}
vector<string> get_variants(int n) {
vector<string> result = {"0", "1"};
vector<string> temp;
temp.reserve(2);
result.reserve(2);
for (int i=0; i < (n - 1); ++i) {
copy(result.begin(), result.end(), temp.end()); // [1]
for (int j=0; j < result.size(); ++j) {
temp[j] += "0";
result[j] += "1";
}
copy(temp.begin(),temp.end(), result.end());
temp.clear();
}
return result;
}
int main(int argc, char const *argv[]) {
int n;
cin >> n;
vector<string> maybe = get_variants(n);
print_array(maybe);
return 0;
}
But vector temp is empty, before copying in line which I marked [1] and after. So, my program's output was [0111, 1111]. What I'm doing wrong?
A more straightforward way than using std::copy is the use of .insert():
temp.insert(temp.end(), result.begin(), result.end()); //1
...
result.insert(result.end(), temp.begin(), temp.end()); // 2nd copy
You are writing to temp.end() and result.end(). These iterators represent "one past the end", and therefore writing to these iterators is Undefined Behavior.
You seem to be looking for std::back_inserter. This will create an iterator that will insert a new element to your container when it is written through.
std::copy(result.begin(), result.end(), std::back_inserter(temp));
While this answers the posted question, there remain other errors in your code leading to Undefined Behavior.
Trying to compile your program with a C++ compiler will not work, because you include #include <bits/stdc++.h>which is a non tC++ standard compliant header.
You should never include this file.
You are using typical competitive programming stuff, but including all C++ headers and not use them will eat up Compile time for no good reason.
Then, you typedef the typical competitive programming abbreviations. 2 of them, you do not use. Then there is no reason to define them.
I recommend to not do this any longer. And in C++, please use the using statement.
Then, although you want to be fast, you pass arr by value to your print function. This will copy the whole vector.
You assign/compare a lot of int with unsigned int values. This you should not do.
Additionally: Please use meaningful variable names and write comments. The more the better.
Regarding your specific bug. Both std::copy statements use end iterator as target. End is end. It is past the end of the vector. Please use std::back_inserter instead.
Regarding the algorithm. I took a while for me to realize that you basically want to create binary numbers. Nothing else. Unfortunately you translated that in a very complicated way.
Normally, you just would count from 0 to 2^n-1 and then show the data. Thats all. Becuase the numbers may be of arbitraty length, we will use manual addition of digits like in scholl on a peice of paper. Very simple.
Everthing then biols down to some lines of code.
Please see:
#include <iostream>
#include <vector>
int main() {
// Read length of binary number to create and validate input
if (int numberOfDigits{}; (std::cin >> numberOfDigits and numberOfDigits > 0)) {
// Here we will store the binary digits, so 0s or 1s
std::vector<int> digits(numberOfDigits,0);
// Som printing helper
std::cout << '[';
bool printComma{};
// We need to print 2^n possible combinations
for (int i = 0; i < (1 << numberOfDigits); ++i) {
// Print comma, if need
if (printComma) std::cout << ','; printComma = true;
// Print all digits of the binary number
for (const int d : digits) std::cout << d;
// Calculate next binary number
int carry = 0;
for (int index=numberOfDigits -1; index >=0; --index) {
const int sum = digits[index] + ((index == (numberOfDigits - 1)?1:0)) + carry;
carry = sum / 2;
digits[index] = sum % 2;
}
}
std::cout << ']';
}
}
If there should be questions, then I am happy to answer.
i am writing a function that will return the string with common prefix of all string in a given array.But i am not able to return the string as its size is still showing as zero.
string Solution::longestCommonPrefix(vector<string> &A) {
string s;
int k=A.size();
int m=A[0].size();
for(int i=1;i<k;i++)
{
int j=A[i].size();
if(j<m) m=j;
}
int f;
for(int i=0;i<k-1;i++)
{
for(f=0;f<m;f++)
{
if(A[i][f]==A[i+1][f])
{
s[f]=A[i][f];
}
else break;
}
cout<<s.size();
}
return s;
}
As I mentioned in the comments, the size of your string, s, is always zero since you are never actually changing its size. The size of a string can change in a few ways, through assignment (=, +=), and resize being two. Your program currently has undefined behaviour, since, when you do s[f]=A[i][f], you are modifying s at index f, even though s has no contents.
So how do you fix this? Initially, you can resize s to the size of m, and fill it temporarily with spaces. Now, there's still a logic problem in your if statement. Specifically, with the else, since if the else is reached, you need to cut off anything remaining, and change m. See the below for a full working program:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
string longestCommonPrefix( const vector<string> &A ) {
string s;
int k = A.size();
int m = A[0].size();
for ( int i = 1; i < k; i++ ) {
int j = A[i].size();
if ( j < m ) m = j;
}
int f;
s.resize( m, ' ' ); // temporary, just to set the contents
for ( int i = 0; i < k - 1; i++ ) {
for ( f = 0; f < m; f++ ) {
if ( A[i][f] == A[i + 1][f] ) {
s[f] = A[i][f]; // copy the similar values
} else {
m = f; // if we reach a character which is not the same, then we reset m
s.resize( m ); // and resize the string
}
}
}
return s;
}
int main() {
vector<string> a;
a.push_back( "hello" );
a.push_back( "hell" );
a.push_back( "help" );
a.push_back( "he" );
cout << longestCommonPrefix( a );
getchar();
}
The above will have an output of he, which is the common prefix of all three words.
The below is a modified version of the function. First, I've replaced int with size_t, which should be used for any sizes. Second, it introduces a few error checks and simplifications. If the input vector is size 0, then don't do any checks and return an empty string. If the size is 1, then just return the contents of the element. No work needed.
After this, assume that A[0] is the entire prefix which belongs to all elements in the vector. In the for loop, you would then look for when this is not true, and resize the string accordingly. You will notice that the loop starts at 1, since we are assuming the first element is the full prefix. The inner loop also is less than s.size(), so that as s shrinks, it is accounted for.
string longestCommonPrefix( const vector<string> &A ) {
size_t k = A.size();
if ( k == 0 )
return "";
if ( k == 1 )
return A[0];
string s = A[0];
for ( size_t i = 1; i < k - 1; i++ ) {
if ( A[i].size() < s.size() ) s.resize( A[i].size() );
for ( size_t f = 0; f < s.size(); f++ ) {
if ( A[i][f] != A[i + 1][f] ) {
s.resize( f );
}
}
}
return s;
}
EDIT: There was an issue in the second version, with going out of bounds. UB again (oops). I added in a check, inside the first for loop, which now resizes s if it is larger than A[i]
You're indexing into a string that's uninitialized. When you do s[f]=A[i][f];, you're actually introducing Undefined Behavior into the mix - you might be writing to the string's memory or over something else entirely. No matter the behavior, you aren't triggering any of the string's internal counters that the C++ class exposes for you.
Instead, try doing s += A[i][f]. std::string exposes the += operator for you to append characters to an existing string. You can read about that and much more that your std::string can do here: http://www.cplusplus.com/reference/string/string/
As others have mentioned there is undefined behaviour at s[f]=A[i][f]; and also gave implementations, however Here is another version for c++14 or above with stl algorithms,
#include<algorithm>
#include<string>
#include<numeric>
#include<vector>
std::string longest_common_prefix(const std::vector<std::string>& v) {
if (v.size() == 0) {
return "";
}
auto begin = std::begin(v[0]), end = std::end(v[0]);
end = std::accumulate(std::begin(v) + 1, std::end(v), end, [begin](auto end, const auto& s) {
return std::mismatch(begin, end, std::begin(s), std::end(s)).first;
});
return std::string(begin, end);
}
Write a void function called string_list_sort() that reads in any number of strings (duplicates are allowed) from cin, stores them in a vector, and then sorts them. Don’t use the standard C++ sort function here — use the version of quicksort that you created.
My problem is I tried to use strcmp() but I got a lot of errors, so I tried this method, but I have a problem with char val = v[end]. I am not sure how to compare two std::string values.
I changed char to string and it works. Now my problem is for example v = {" apple", "car", "fox", " soap", "foz"}; the result I get is apple, soap, car, fox, foz which is not in alphabetical order
#include <iostream>
#include <string>
#include <cstdio>
#include <cstring>
#include <vector>
#include "error.h"
using namespace std;
void string_list_sort(vector<string> v){
string line;
while (getline(cin, line)){
if (line.empty()){
break;
}
v.push_back(line);
}
}
int partition(vector<string>&v, int begin, int end)
{
char val = v[end];
char temp;
int j = end;
int i = begin - 1;
while (true)
{
while (v[++i] < val)
while (v[--j] > val)
{
if (j == begin)
break;
}
if (i >= j)
break;
temp = v[i];
v[i] = v[j];
v[j] = temp;
}
temp = v[i];
v[i] = v[end];
v[end] = temp;
return i;
}
void quicksort(vector<string>& v, int begin, int end)
{
if (begin < end)
{
int p = partition(v, begin, end);
quicksort(v, begin, p - 1);
quicksort(v, p + 1, end);
}
}
void quick_sort(vector<string>& v)
{
quicksort(v, 0, v.size() - 1);
}
int main()
{
vector<string> v;
v =
{ " this is a test string,.,!"};
string word;
while (cin >> word)
{
v.push_back(word);
}
quick_sort(v);
for (int i = 0; i < v.size(); i++)
{
cout << v[i] << " ";
}
}
OP almost has a sorting function. Two mistakes in particular stand out:
char val = v[end];
char temp;
v is a vector<string> so v[end] will return a string.
string val = v[end];
string temp;
Takes care of that and makes the program compile and successfully sort. There is no need to go inside the strings to compare character by character. string does that work for you.
The second problem: Quicksort's partition function is supposed to look like (Looting from wikipedia here)
algorithm partition(A, lo, hi) is
pivot := A[lo]
i := lo – 1
j := hi + 1
loop forever
do
i := i + 1
while A[i] < pivot
do
j := j – 1
while A[j] > pivot
if i >= j then
return j
swap A[i] with A[j]
and OP's partition function has picked up a bunch of extra baggage that needs to be removed to get an optimal mark from their instructor. Take a look at the above pseudo implementation and compare it with yours. You may see the mistakes right way, but if not, stand on the shoulders of giants and translate it into C++ (hints: := is plain old = in C++, and you'll need to add some ;s and braces). Debug the result as required. I won't translate it because that would almost totally defeat the point of the assignment.
Side notes (gathering a few important comments):
When writing a test driver don't take in user input until you know the algorithm works. Start with preloaded input that is easy to visualize like
int main()
{
vector<string> v{"C","B","A"};
quick_sort(v);
for (size_t i = 0; i < v.size(); i++)
{
cout << v[i] << " ";
}
}
When the output is "A B C ", change the input to something more complicated, but still easy to visualize
vector<string> v{"A","C","Q","B","A"};
And when that works go nuts and feed it something nasty. I like the Major General's Song from the Pirates of Penzance.
You can compare strings using std::string::compare() or relational operators.
It looks like you've tried using relational operators here, but as #user4581301 pointed out, in partition() on the first line, you have
char val = v[end];
However, v[end] is of type 'string', not 'char'. If you declare val and temp as string instead of char, you can sort them with the relational operators you have, and I think you'll be fine.
compare() documentation: fttp://www.cplusplus.com/reference/string/string/compare/
Relational operators: http://www.cplusplus.com/reference/string/string/operators/
Where is this code wrong?
It won't let me cast strlen(s) into an int that I can iterate it until i is equal to the length of the string.
#include <iostream>
#include <string.h>
#include <string>
using namespace std;
int main()
{
string s;
cin >> s;
for (int i = 0; int n = (int)strlen(s); i < n, i++)
{
cout << s[i] << endl;
}
}
The problem is not that the result of strlen can't be cast to an int, but that strlen can't be used with std::string.
strlen is for "C strings", zero-terminated arrays of characters.
std::string has a size member function:
int main()
{
string s;
cin >> s;
for (int i = 0; i < s.size(); i++)
{
cout << s[i] << endl;
}
}
There is nothing inside the C header <string.h> that applies to std::string.
A reference can be useful.
strlen is for char arrays.
std::string has a member function called size and length.
If you still want to use strlen, you can call c_str and pass the returned string to strlen.
std::size_t length = s.size();
for (int i = 0; i < length; ++i)
You can also iterate over the elements of the std::string:
for (std::string::iterator itr = s.begin(); itr != s.end(); ++itr)
{
std::cout << *itr << std::endl;
}
Because strlen expects to get a char const* as it's argument. You should probably use s.size() instead as s is a std::string.
In addition you should probably not compute strlen inside a loop like that due to performance issues (s.size on the other hand should be able to complete in O(1) time so it would be OK).
Then there's a few other problems with your program, already at line one. You can't include a file by using #include //iostream, you should use #include <iostream> instead.
Second you cannot declare a variable in the condition of a for loop as you try to do, and you probably shouldn't assign instead of comparing (one equal sign is not the same as two). You should have written for( int i = 0; i != s.size(); i++ )
Third you shouldn't do the check in the update expression in the for construct. What goes there will only be evaluate to update the loop variables and such and the truth value will be disregarded.
Overall I think you should pick up an introduction to C++ book or find a good tutorial online. Your code simply has to much problems to conclude that you have learnt even the most basic C++.
very basic C++ question. Looks I m really rusted there...
All I want to do is to read an array of X strings from a file and create an array of X vertical strings of the horizontal strings.
IE :
file contains:
azert
qsdfg
wxcvb
poiuy
mlkjh
I want to create a string array containing:
aqwpm
zsxol
edcol
rfvuj
tgbyh
Here is what I tried so far:
[bad code]
const int SIZE = 37;
std::string table_h[SIZE];
std::string table_v[SIZE];
int i = 0;
while (source >> table_h[i]) //,sizeof table_h[i]
{
for (int j = 0; j< SIZE; j++)
{
table_v[j][i] = table_h[i][j];
}
i++;
}
-> works fine for the first line, breaks when i=1. I don't understand what.
I noticed that although table_v[0][0] = 'f'; works fine.
Both table_v[0][36] = 'f'; and table_h[0].at(36); break.
With char * (which was my first idea),
char * table_h[SIZE];
char * table_v[SIZE];
something like
table_v[0][0] = 'f';
immediately breaks.
I suppose I need to allocate memory or initialize something first??
Thx in advance.
You should set the size of strings before using operator [] to access them. Resize of table_h is optional, but you definitely have to resize table_v.
const int SIZE = 37;
std::string table_h[SIZE];
std::string table_v[SIZE];
for (size_t i = 0; i < SIZE; ++i)
{
table_h[i].resize(SIZE);
table_v[i].resize(SIZE);
}
int i = 0;
while (source >> table_h[i])
{
for (int j = 0; j < SIZE; j++)
{
table_v[j][i] = table_h[i][j];
}
i++;
}
See the working example.
In my opinion, if you know the size of a strings, resizing is better than appending. It can save some memory re-allocations, and IMHO it is simply nicer solution.
Indeed the table_v[j] is an empty string.
The string needs to allocate space for the characters. This is not done by the index operators, i.e.
table_v[j][9] = 'a';
assumes enough space is allocated for table_v[j].
You can do append to your string to add to the initially empty string. Append does not take chars though, so instead of using index of table_h[i][j] you can use substr.
std::string to_append = table_j[i].substr(j, 1)
table[j].append(to_append);
This also relieves you of the i counter.
Here is a demonstrative program that shows how it can be done
#include <iostream>
#include <vector>
#include <string>
#include <numeric>
int main()
{
std::vector<std::string> v1 =
{
"azert", "qsdfg", "wxcvb", "poiuy", "mlkjh"
};
for ( const std::string &s : v1 ) std::cout << s << ' ';
std::cout << std::endl;
auto max_size = std::accumulate( v1.begin(), v1.end(),
size_t( 0 ),
[]( size_t acc, const std::string &s )
{
return acc < s.size() ? s.size() : acc;
} );
std::vector<std::string> v2( max_size );
for ( const std::string &s : v1 )
{
for ( std::string::size_type i = 0; i < s.size(); i++ )
{
v2[i].push_back( s[i] );
}
}
for ( const std::string &s : v2 ) std::cout << s << ' ';
std::cout << std::endl;
return 0;
}
The program output is
azert qsdfg wxcvb poiuy mlkjh
aqwpm zsxol edcik rfvuj tgbyh
As for your code than these statements
std::string table_h[SIZE];
std::string table_v[SIZE];
defined two arrays of empty strings. So you may not apply the subscript opertaor to an empty string. You could use for example member function push_back
for (int j = 0; j< SIZE; j++)
{
table_v[j].push_back( table_h[i][j] );
}