C++ how to insert wstring into vector at given position - c++

I am wondering, if anyone could explain to me the second argument in the vector.insert() method:
iterator insert (iterator position, const value_type& val);
For example, I have a vector of type wstring and I would like to insert a wstring at a given position. I have figured out how to set the position using an iterator:
wstring word = "test";
int insertion_pos = 3;
iterator it = words.begin();
words.insert( it + insertion_pos, word );
But what about that second argument? How can I pass a wstring object to the insert() method?
Thanks a lot.
Cheers,
Martin
Full example:
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <wchar.h>
#include <vector>
using namespace std;
int main(void) {
// Initialize the vecor with three words.
vector<wstring> words;
wstring word1 = "FirstWord"; // Error msg: no viable conversion from 'const char [10]' to 'wstring' (aka
// 'basic_string<wchar_t>')
wstring word2 = "SecondWord"; // same here
wstring word3 = "ThirdWord"; // same here
words.push_back(word1);
words.push_back(word2);
words.push_back(word3);
// Now try to insert a new word at position 2 (i.e. between "SecondWord "and "ThirdWord"
int position = 2;
wstring word4 = "InsertThis"; // same error as above
iterator it = words.begin(); // Error: use of class template iterator requires template
// arguments
words.insert( it + position, word4 );
// Invalid arguments ' Candidates are: __gnu_cxx::__normal_iterator<std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>
// *,std::vector<std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>,std::allocator<std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>>>>
// insert(__gnu_cxx::__normal_iterator<std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>
// *,std::vector<std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>,std::allocator<std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>>>>,
// const std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>> &) void
// insert(__gnu_cxx::__normal_iterator<std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>
// *,std::vector<std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>,std::allocator<std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>>>>,
// unsigned long int, const std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>> &) void
// insert(__gnu_cxx::__normal_iterator<std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>
// *,std::vector<std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>,std::allocator<std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>>>>,
// #10000, #10000) '
return EXIT_SUCCESS;
}

Thanks for the clear example of the issue. Here is a modified version with some comments about changes. It compiles for me using clang on Mac OS X.
One change is the "L" in front of the string literal. This is an indicator that the string literal to follow is of type wchar_t. See also this.
Wide character/unicode/utf support is something I would add only if it's needed in the problem you're trying to solve.
// #include <stdio.h> prefer "cstdio" to stdio.h; not used in example
// #include <stdlib.h> same
#include <iostream>
#include <string>
// #include <wchar.h> not used in example
#include <vector>
using namespace std;
// simplify to main()
int main() {
// Initialize the vecor with three words.
vector<wstring> words;
wstring word1(L"FirstWord"); // Use Constructor, no assignment operator=
wstring word2(L"SecondWord");
wstring word3(L"ThirdWord");
words.push_back(word1);
words.push_back(word2);
words.push_back(word3);
int position = 2;
wstring word4(L"InsertThis");
// iterator depends on type of container
vector<wstring>::iterator it = words.begin();
words.insert( it + position, word4 );
for (const std::wstring& w : words)
std::wcout << w << " ";
std::wcout << std::endl;
return EXIT_SUCCESS;
}
Understanding the insert call
The prototype for the vector's insert member function is:
iterator insert( iterator pos, const T& value );
where T is the type you give as a template parameter, i.e. std::wstring in this case.
Iterators have operator+ overloaded, with the following semantics: iterator it + integer 2 returns a new iterator with a position 2 "increments" past the iterator it.
words.insert( it + position, word4 );
Suggestion
One thing to be careful about it how you determine an inerstion position.
I think it would be better practice (more maintainable) to use an iterator to "walk along" the vector, rather than using iterator+offset. If you're not very comfortable with iterators, this would be a chance to learn how to use them.
This would avoid a potential situation, discussed in a previous version of this answer, where you accidentally offset your iterator past the end of the vector, leading to a segmentation violation.

Related

How to shuffle an array in C++?

I have an array:
names[4]={john,david,jack,harry};
and i want to do it randomly shuffle, like:
names[4]={jack,david,john,harry};
I tried to use this but it just shuffled the letters of the first word in the array:
random_shuffle(names->begin(), names->end());
Here is the full code, it reads names from a .txt file and puts in an array:
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
using namespace std;
int main() {
ifstream readName("names.txt");
string names[197];
int i = 0;
for (string line; getline(readName, line); ){
readName >> names[i];
i++;
}
readName.close();
random_shuffle(names->begin(), names->end());
for (int i = 0; i < 197; i++) {
cout << names[i] << endl;
}
return 0;
}
I tried few other things from different people but I couldn't manage to work it.. Anything helps, thank you!
Here's your code with what I felt were the smallest amount of changes. One could argue that I didn't need to change your first for loop as much, but I figure that if you have the prescience to know how many names you're reading, you might as well use the knowledge.
#include <algorithm>
#include <fstream>
#include <iostream>
#include <iterator> // std::begin(), std::end(); required for C-arrays
#include <random> // std::mt19937; needed to feed std::shuffle()
#include <string>
// using namespace std; // BAD PRACTICE
int main() {
constexpr int size = 4; // Give your magic number a name; only need to change
// a single location
std::ifstream readName("names.txt");
if (!readName) { // Always check that you successfully opened the file.
std::cerr << "Error opening file.\n";
return 1;
}
std::string names[size];
// int i = 0;
for (int i = 0; i < size; ++i) { // Retool the loop entirely
std::getline(readName, names[i]);
}
readName.close();
// This is a fragile solution. It's only working because the array is in
// scope
std::shuffle(std::begin(names), std::end(names),
std::mt19937{std::random_device{}()});
for (int i = 0; i < size; i++) {
std::cout << names[i]
<< '\n'; // Don't use std::endl unless you actually need it
}
return 0;
}
This is not ideal code, though. Any change to the size of the input file requires changing the code and re-compiling. The biggest single change was to get rid of std::random_shuffle and use std::shuffle() instead. std::random_shuffle was deprecated with C++14 and removed in C++17. It's bad to use it. std::shuffle() does add the requirement of providing a PRNG, but it's not so bad. It leads to better code if you have a PRNG that needs to randomize many different things in a bigger program. This is because it's good to have a single PRNG and let it live for the length of your program as opposed to constantly building new ones.
And the C-array just makes things a bit clunkier. Enter std::vector.
#include <algorithm>
#include <fstream>
#include <iostream>
#include <iterator>
#include <random> // std::mt19937; needed to feed std::shuffle()
#include <string>
#include <vector>
int main() {
std::ifstream readName("names.txt");
if (!readName) { // Always check that you successfully opened the file.
std::cerr << "Error opening file.\n";
return 1;
}
std::vector<std::string> names;
std::string name;
while (std::getline(readName, name)) { // Retool the loop entirely
names.push_back(name);
}
readName.close();
std::shuffle(std::begin(names), std::end(names),
std::mt19937{std::random_device{}()});
for (const auto& i : names) {
std::cout << i << '\n';
}
return 0;
}
The vector can grow as needed, so you see how much simpler the loop that reads the names becomes. It's also more flexible since you don't have to know ahead of time how many entries to expect. It will "just work." With the call to std::shuffle() I kept the std::begin(names) syntax because many consider this a best practice, but you could have also used names.begin() if you wanted since the vector class provides its own iterators.
Lets have a look at you main question:
I tried to use this but it just shuffled the letters of the first word in the array:
random_shuffle(names->begin(), names->end());
The reason that it only shuffles the first word is because of the types and usage.
So names is an array of strings.
string names[197];
The problem stems from the C world. Were arrays decay into pointers exceedingly easily (just by being used in an expression). So here names-> has decayed into a pointer to the first element of the array. This allows you to use the -> operator which normally only works on pointers. So you are calling the functions begin() and end() on the pointer to the first element in the array. Thus only the first name is being shuffled.
The fix this problem use std::begin() method.
// here std::begin / std::end find the beginning and end
// of the array. So you are shuffling the array.
random_shuffle(std::begin(names), std::end(names));
But I would note that random_shuffle() is outdated. As mentioned by #sweenish you should use std::shuffle() See his answer for details.
A couple of things we can improve:
You use C array to store the names. Sure it works, but it is susceptible to a couple of issues because it can not be re-sized (and unless you think the file is never going to be changed that may be an issue). Potentially a hidden issue to a far distant maintainer.
std::vector<std::string> names; // resizeable container.
I would note that the current implementation ignores the first line. Then reads the first word from each subsequent line. There is also a slight issue that the last line may be empty and you read an empty name into the last element of the array (but you don't track how many names you read so unless you use all elements in the array you may never notice that).
I would change that. As it is not obvious. I would delibrately and seprately ignore the first line. Then I would simply read all the first words into a vector (so you know the size).
std::string line
std::getline(file, line); // Ignore the first line.
std::string word
while(file >> word) {
names.push_back(word);
std::getline(file, line); // ignore the rest of the line.
}
We could get fancy. Use iterators to simply create the array directly.
class Line
{
std::string firstWord;
friend std::istream& operator>>(std::istream& stream, Line& data) {
stream >> data.firstWord;
stream.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); retrun stream;
}
operator std::string() const {
return firstWord;
}
};
Now you can create and load the vector in one line:
std::vector<std::string> names(std::istream_iterator<Line>(file),
std::istream_iterator<Line>{});
Then finally copy the names out can be made easier using foreach loop. Also don't use std::endl in a loop like this. It forces a flush of the underlying bugger after each new line. This is very ineffecient.
for(auto const& name: names) {
std::cout << name << "\n";
}
So the result is:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
class Line
{
std::string firstWord;
friend std::istream& operator>>(std::istream& stream, Line& data) {
stream >> data.firstWord;
stream.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); return stream;
}
operator std::string() const {
return firstWord;
}
};
int main()
{
std::ifstream file("names.txt");
std::string line
std::getline(file, line); // Ignore the first line.
std::vector<std::string> names(std::istream_iterator<Line>(file),
std::istream_iterator<Line>{});
random_shuffle(std::begin(names), std::end(names));
for(auto const& name: names) {
std::cout << name << "\n";
}
}

I am trying to push each letter of a word into a vector, but it is throwing an error

This is my code:
#include <iostream>
#include <string>
#include <bits/stdc++.h>
using namespace std;
int main()
{
string word = "hi";
int i = 0;
vector<string> vec;
for(i ; i < word.length() ; i++)
{
vec.push_back(word[i]);
}
return 0;
}
I am trying to push each letter of string "hi" into a vector vec using for loop, but, it is throwing an error on the 14th line: "error: no matching function for call to ‘std::vector >::push_back(char&)’"
Indexed access ([] operator) on std::string returns char& and not std::string itself.
Vector declared is vector of string so insertion into vector requires string type not char&
If you want to have vector of char, change accordingly
You get the error because you have a vector of strings, not characters.
Change it to a vector of characters and it should work:
std::vector<char> vec;
As for what you're trying to do, there is a simpler way to do it:
std::vector<char> vec(begin(word), end(word));
The error lies in the fact that you have a std::vector of std::string's, but you are trying to push_back a char. There are multiple solutions to this:
Change your std::vector<string> to a std::vector<char>
Create a new std::string object every time you want to push_back a char like this (This is using an overloaded std::string constructor but there are many more possibilities.):
vec.push_back(string(1,word[i]));
Note: Please consider reading about Why is “using namespace std;” considered bad practice?.

Rotate last n elements of array in C++

I'm trying to implement a function that deletes a character from a string wherever the current index is. Below is a skeleton of what I have so far. I'm trying to rotate the character I want to remove to the end of the string then replace it with a null terminator. The code I have below does not seem to actually rotate buffer because the output I'm getting is "wor" instead of the expected output "wrd".
int main() {
char buffer[]="word";
int currIndex=2;
int endIndex=strlen(buffer);
currIndex--;
endIndex--;
rotate(buffer+currIndex,
buffer+1,
buffer+strlen(buffer));
buffer[endIndex]='\0';
cout << buffer << endl;
return 0;
}
This doesn't attempt to answer the question being asked, but rather solve the underlying problem: Removing a single character from a string.
The solution is a simple application of the std::string::erase class member:
#include <string>
#include <iostream>
int main() {
std::string word{ "word" };
std::string::size_type currIndex{ 2 };
word.erase( currIndex, 1 );
std::cout << word << std::endl;
}
Using a std::string makes things way easier because I don't have to think about pointers:
std::string buffer="word";
rotate(buffer.begin()+1, buffer.begin()+2, buffer.end());
buffer.resize(buffer.size()-1);
Demo
Alternatively, we can stick with a c-style array:
char buffer[]="word";
rotate(buffer+1, buffer+2, buffer+4);
buffer[3] = '\0';
Demo2
std::rotate accepts 3 arguments:
template< class ForwardIt >
ForwardIt rotate( ForwardIt first, ForwardIt n_first, ForwardIt last );
first is the first element in the range you want to left rotate.
nfirst is the element you want to be at the start of the range after you've rotated (this tells the algorithm how many times to left rotate, effectively)
last is the last element in the range you want to rotate.
Your code:
char buffer[]="word";
int currIndex=2;
int endIndex=strlen(buffer);
currIndex--;
endIndex--;
rotate(buffer+currIndex,
buffer+1,
buffer+strlen(buffer));
buffer[endIndex]='\0';
Was actually really close. You just got the second argument wrong. It should have been
rotate(buffer+currIndex,
buffer+2,
buffer+strlen(buffer));
buffer[endIndex]='\0';
But the code was admittedly a bit confusing written with the increments and decrements.

type inference for std::initializer_list

If I write this
std::vector<std::string> v{"one","two","three"};
What is the type inferred to the associated std::initializer_list template ?
In other words, when the char * string literals are converted to std::string ?
It's a better idea to declare it as
std::vector<std::string> v{std::string("one"),
std::string("two"),
std::string("three")};
to avoid issues connected to the type-deduction mechanism of the templates involved ?
I'll keep the same optimizations with this ?
Update: To answer your question about type inference:
The initializer list constructor of vector<string> takes an initializer_list<string>. It is not templated, so nothing happens in terms of type inference.
Still, the type conversion and overload resolution rules applied here are of some interest, so I'll let my initial answer stand, since you have accepted it already:
Original answer:
At first, the compiler only sees the initializer list {"one","two","three"}, which is only a list of initializers, not yet an object of the type std::initializer_list.
Then it tries to find an appropiate constructor of vector<string> to match that list.
How it does that is a somewhat complicated process you would do best to look up in the standard itself if you are interested in the exact process.
Therefore, the compiler decides to create an actual object of std::initializer_list<string> from the initializer list, since the implicit conversion from the char*'s to std::strings makes that possible.
Another, maybe more interesting example:
std::vector<long> vl1{3};
std::vector<string> vs1{3};
std::vector<string> vs2{0};
What do these do?
The first line is relatively easy. The initializer list {3} can be converted into a std::initializer_list<long> analogous to the {"onm", "two", "three"} example above, so you get a vector with a single element, which has value 3.
The second line is different. It constructs a vector of 3 empty strings. Why? Because an initializer list {3} can by no means be converted into an std::initializer_list<string>, so the "normal" constructor std::vector<T>::vector(size_t, T = T()) kicks in and gives three default-constructed strings.
Well this one should be roughly the same as the second, right? It should give an empty vector, in other words, with zero default-constructed strings. WRONG!. The 0 can be treated as a nullpointer constant, and validates the std::initializer_list<string>. Only this time the single string in that list gets constructed by a nullpointer, which is not allowed, so you get an exception.
There is no type inference because vector provide only a fully specialized constructor with the initializer list. We could add a template indirection to play with type deduction. The example below show that a std::initializer_list<const char*> is an invalid argument to the vector constructor.
#include <string>
#include <vector>
std::string operator"" _s( const char* s, size_t sz ) { return {s, s+sz}; }
template<typename T>
std::vector<std::string> make_vector( std::initializer_list<T> il ) {
return {il};
}
int main() {
auto compile = make_vector<std::string>( { "uie","uieui","ueueuieuie" } );
auto compile_too = make_vector<std::string>( { "uie"_s, "uieui", "ueueuieuie" } );
//auto do_not_compile = make_vector( { "uie","uieui","ueueuieuie" } );
}
Live demo
From http://en.cppreference.com/w/cpp/language/string_literal:
The type of an unprefixed string literal is const char[]
Thus things go this way:
#include <iostream>
#include <initializer_list>
#include <vector>
#include <typeinfo>
#include <type_traits>
using namespace std;
int main() {
std::cout << std::boolalpha;
std::initializer_list<char*> v = {"one","two","three"}; // Takes string literal pointers (char*)
auto var = v.begin();
char *myvar;
cout << (typeid(decltype(*var)) == typeid(decltype(myvar))); // true
std::string ea = "hello";
std::initializer_list<std::string> v2 = {"one","two","three"}; // Constructs 3 std::string objects
auto var2 = v2.begin();
cout << (typeid(decltype(*var2)) == typeid(decltype(ea))); // true
std::vector<std::string> vec(v2);
return 0;
}
http://ideone.com/UJ4a0i

Reverse a word using function call

How can input a word and reverse the output of it. I made a function to calculate the length of the word and from here I have to reverse the word depending on the length of it.
How can I do that?
#include<iostream>
using std::cout;
using std::endl;
using std::cin;
int LengthOfString( const char *); // declaring prototype for length of the string
int reverse(const char []);
int main()
{
char string1[100];
cout<<"Enter a string: ";
cin>>string1;
cout<<"Length of string is "<<LengthOfString(string1);
system("PAUSE");
return 0;
}
int LengthOfString( const char *x)
{
int index;
for(index = 0; *x!='\0';x++,index++);
return index;
}
int reverse(const char y[])
{
/* my attempted loop, its not right i know.
a[] = *index; // length of the word
for(int i=0; i<=index/2; i++)
for(j=0; j == length, j--) */
}
This wheel has already been invented, and exists in the standard library.
#include <iostream>
#include <string>
#include <algorithm>
int main()
{
std::string word;
std::cout << "Enter a word: ";
std::cin >> word;
std::reverse(word.begin(), word.end());
std::cout << "Reverse: " << word << std::endl;
return 0;
}
To understand exactly what's going on here, there are a few things that you must cover first:
data structures (classes)
containers
iterators
I hope you already know what a class is. In case you're still in introductory stuff, a class is basically a user defined collection of state and behavior. The author can choose to restrict access to the state or behavior of a class for a variety of reasons. In the case of std::string, the standard library string class, all of the state is hidden and only behavior is accessible.
The string class is a container that contains characters. There are numerous other container classes, each of which with different strengths and weaknesses. The string class contains a sequence of characters with a strict order. Other containers exist, such as std::set, std::vector, std::list, and others. std::string bears a passing resemblance to std::vector, and is a distant cousin of std::list. Each collection behaves differently and is suited for different things.
You might think you need to understand how the string class stores its data in order to reverse it, but you don't. This is where iterators come in. std::string owns a typedef, std::string::iterator, which is a special object which stores the location of a single element in a string. std::reverse is a library function which takes 2 iterators and repeatedly swaps their contents and moves them towards each other. This looks like this as it's happening:
v v <-- positions of iterators (start at the start, end at the end)
ABC <-- initial state
v v <-- the end iterator moved back
ABC
v v
CBA <-- the iterators swapped their values
vv <-- the begin iterator moved forward
CBA
V <-- the end iterator moved back; both iterators are in the same place
CBA <-- therefore, we're done, the string is reversed
One thing about iterators is they're kind of like pointers. In fact, you can pass pointers to some functions that expect iterators because they behave syntactically the same. Therefore, you should be able to write your own reverse function that uses pointers that basically does the same thing this did, except with char *s.
Here's some pseudocode that you should be able to write the function with (I won't write it out completely because it's homework):
namespace BaidNation
{
void reverse(char *begin, char *end)
{
loop forever
{
if (end equals begin):
done;
move end backwards;
if (end equals begin):
done;
swap end's and begin's characters;
move begin forwards;
}
}
}
Keep in mind that BaidNation::reverse (as well as std::reverse) expects for end the iterator that references the element AFTER the end of the collection, not the one that references the last element. How does it then make sense to use this?
Your LengthOfString function returns the number of non-null characters in a string. Since arrays are zero-indexed, we know that, like any other array, if we check string1 + LengthOfString(string1), we'll get a pointer to the character after the end which is, for once, exactly what we want.
Thus, we can use this to reverse the string:
BaidNation::reverse(string1, string1 + LengthOfString(string1));
If you have to use exactly the signature earlier, you can adapt this design into the other one:
int reverse(const char str[])
{
char *start = str, *end = str + LengthOfString(str);
BaidNation::reverse(start, end);
}
Based on the fact that the return type of your prototype function is int, it looks to me like you want to do an in-place reversal of a string. You first need to find out how long the string is (although you computed that before, you didn't pass the result to this function), then swap elements until you get to the middle. To make this work you need to pass, not a const char[], but just a char* (indicating that you will be changing the content):
int reverse(char* y)
{
int ii, n;
n = LengthOfString(y); // "no built in functions - otherwise, use strlen()
for(ii=0; ii<n/2;ii++) {
char temp;
temp = y[ii];
y[ii] = y[n - ii - 1];
y[n - ii] = temp;
}
}
Declare a new char* of the same length, and then loop as follows -
for(int i=0;i<stringLength;i++){
newString[i]=oldString[stringLength-i];
}
return newString;
Also you might want to consider using the String class instead of char*.