How to convert string into char *agv[] - c++

I am building a command line tool and at the beginning whole line is a string. How could I convert:
string text = "-f input.gmn -output.jpg";
into
const char *argv[] = { "ProgramNameHere", "-f", "input.gmn", "-output.jpg" };

If I had to use getopt, and I knew I was starting with a white-space separated std::string, I'd do this:
#include <iostream>
#include <string>
#include <sstream>
#include <algorithm>
#include <iterator>
#include <vector>
#include <cassert>
#include <cstring>
int main() {
https://stackoverflow.com/questions/236129/how-to-split-a-string-in-c
// My input
std::string sentence = "-f input.gmn -output.jpg";
// My input as a stream
std::istringstream iss(sentence);
// Create first entry
std::vector<std::string> tokens;
tokens.push_back("ProgramNameHere");
// Split my input and put the result in the rest of the vector
std::copy(std::istream_iterator<std::string>(iss),
std::istream_iterator<std::string>(),
std::back_inserter(tokens));
// Now we have vector<string>, but we need array of char*. Convert to char*
std::vector<char *> ptokens;
for(auto& s : tokens)
ptokens.push_back(&s[0]);
// Now we have vector<char*>, but we need array of char*. Grab array
char **argv = &ptokens[0];
int argc = ptokens.size();
// Use argc and argv as desired. Note that they will become invalid when
// *either* of the previous vectors goes out of scope.
assert(strcmp(argv[2], "input.gmn") == 0);
assert(argc == 4);
}
See also: Split a string in C++?
Postscript: In the solution I provided, I used two language features introduced in C++2011: range-based for loops and type inference.
This code fragment will only compile if your compiler supports thew new features:
for(auto& s : tokens)
ptokens.push_back(&s[0]);
If you have an older C++ compiler, you might need to rewrite it using C++2003 features:
for(std::vector<string>::iterator it = tokens.begin(); it != tokens.end(); ++it)
ptokens.push_back(it->c_str());
or
for(std::vector<string>::size_type i = 0; i < tokens.size(); ++i)
ptokens.push_back(tokens[i].c_str());

I would recommend using boost::program_options to parse your program's arguments.
Otherwise if you are using MSVC, you might want to use the built-in __argc and __argv.
There is no portable way to get your program's image name, so you cannot get that information out of nowhere if you dropped it in the first place by discarding your original argv argument.
You could use the C strtok function to split your arguments ... actually scratch that, just use boost::algorithm::split with any_of(' ').

Related

C++ function equivalent to Python set() function

I was wondering if there's a library function in C that can do the same job as set() in Python.
My purpose of using it is to check the total number of unique character in a string.
Code in Python example:
aString = "abbc"
print(len(set(aString)))
This code will output 3. Since the set of aString is {a,b,c}. Is there something similar I can use in C++?
My purpose of using it is to check the total number of unique character in a string
Yes you can create a std::set from the std::string and then get the sets' size using std::set::size() member function as shown below:
#include <iostream>
#include <string>
#include <set>
int main()
{
std::string aString = "abbc";
//create set from std::string
std::set<char> mySet( aString.begin() , aString.end() );
std::cout<< mySet.size();
return 0;
}
The output of the program can be seen here.
Note in C++ there is also option for std::unordered_set so that you would write:
//create unordered_set from std::string
std::unordered_set<char> mySet( aString.begin() , aString.end() ); //note the unordered_set used here instead of set

Using C++'s reverse(string.begin(), string.end()) Why won't it let me hold it in a new variable?

Hello I am very new to programming and C++. I'm trying to make a program that checks if a string is a palindrome (a word that is the same backwards as it is forwards).
In order to do that I searched online about how to reverse a string and came across the reverse(string.begin(), string.end()) function from <bits/stdc++.h>.
I've made a function that can reverse the string written in the parameters and it works fine:
#include <iostream>
#include <vector>
#include <string>
#include <bits/stdc++.h>
std::string reverseStr(std::string str) {
reverse(str.begin(), str.end());
return str;
}
int main() {
std::cout << reverseStr("word");
}
But when I want to assign the reversed string into a new variable "reversedStr":
#include <iostream>
#include <vector>
#include <string>
#include <bits/stdc++.h>
std::string reverseStr(std::string str) {
std::string reversedStr;
reversedStr = reverse(str.begin(), str.end());
return reversedStr;
}
int main() {
std::cout << reverseStr("word");
}
Then when I try and compile it, it gives me this error.
C:/Program Files/mingw-w64/x86_64-8.1.0-posix-seh-rt_v6-rev0/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/bits/basic_string.h:776:7: note: no known conversion for argument 1 from 'void' to 'std::initializer_list<char>'
The terminal process "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -Command g++ -g main.cpp" terminated with exit code: 1.
If you wouldn't mind explaining what is happening that would be great! Thank you!
reverse reverses a collection in place and doesn't return it. If you want to do it to a new variable, then first copy the string to the variable then reverse that:
// pass the str argument by reference to avoid unnecessary copies
std::string reverseStr(const std::string& str) {
std::string reversedStr = str;
std::reverse(reversedStr.begin(), reversedStr.end());
return reversedStr;
}
As stated in documentation std::reverse() does not return anything so you cannot assign it's return value to a variable. Simplest solution would be:
std::string reverseStr(const std::string &str)
{
return std::string( str.rbegin(), str.rend() );
}
using reverse iterators to initialize and return temporary std::string
std::reverse() is used to reverse the elements within the range given by the two parameters, str.begin() and str.end() in your case. This does not return a new reversed string, instead it reverses the collection itself.
If you want the reversed content in a new variable, you must first copy the original string into a new string and then reverse the new string. Alternatively you could use std::reverse_copy() which copies the reverse contents to a new string without affecting the original. It takes in a third parameter that tells where the reversed content must be copied. Do note the reversed string variable must first be resized to the original string's size.
std::string reverseStr(std::string& str) {
std::string reversedStr;
reversedStr.resize(str.size());
std::reverse_copy(str.begin(), str.end(), reversedStr.begin());
return reversedStr;
}
Some additional info: std::reverse() and std::reverse_copy() are present in the <algorithm> header file. <bits/stdc++.h> is non-standard and compiler specific and hence should be avoided. Check this answer for more details: Why should I not #include <bits/stdc++.h>?

How do I get all characters after a space in C++?

In C++, how do I get ALL of the text after a space. I am trying to make my own coding language, so I want the user to be able to enter (/print (text here)) and print the text the user has entered. I want this to be all in one line; without having the user to input the command, then input the thing they want to output. Thank you to anyone who replies in advance.
Try this way. It will give you all the characters after the first space in the string.
std::string x = "ABC CDEFG HIJKL";
x.substr(x.find(" ") + 1);
Leveraging <algorithm>
The following will work with C++11:
#include <string>
#include <algorithm>
#include <cctype>
#include <iostream>
#include <iterator>
bool is_blank(char ch)
{
return std::isblank(static_cast<unsigned char>(ch));
}
int main() {
std::string inp = "print foo";
auto it = std::find_if(inp.begin(), inp.end(), is_blank);
it = std::find_if_not(it, inp.end(), is_blank);
std::copy(it, inp.end(), std::ostream_iterator<char>(std::cout));
}
Run this code in Compiler Explorer.
Note that we're only iterating over the input string once. Also note that this solution leverages the algorithms which come with the C++ standard library - no raw loops required :-)
Using std::string's find functions
std::string has a ton of built-in functions. I'm pretty sure if C++ could be developed from scratch most of them wouldn't be there. But since we have them we put them to some use:
#include <string>
#include <algorithm>
#include <iostream>
#include <iterator>
int main() {
std::string inp = "print foo";
const std::string whitespace = " \t";
auto i = inp.find_first_of(whitespace);
i = inp.find_first_not_of(whitespace, i);
std::cout << inp.substr(i, inp.size() - i) << std::endl;
}
Run this code in Compiler Explorer.
I prefer the first solution since I find the last line a little more readable. std::copy might also be slightly more efficient. Here std::string::substr() returns a temporary string which gets destroyed once std::cout has printed it. Not ideal in terms of performance which might or might not matter here.

why does char[1] read entire word from my input file?

this is what I have done till now: I want to read words from file in C++ and I am allowed to use only cstring library. this is my piece of code
#include <cstring>
#include <fstream>
#include <stdio.h>
using namespace std;
int main(){
ifstream file;
char word[1];
file.open("p.txt");
while (!file.eof()){
file >> word;
cout << word << endl;
}
system("pause");
return 0;
}
It is working fine and reading one word at a time. But I don't understand how this is working fine.
How can char array of any size be it char word[1] or char word[50] read only one word at a time ignoring spaces.
And further I want to store these words in dynamic array. How can I achieve this? Any guidance would be appreciated?
Your code has undefined behaviour. operator >> simply overwrites memory beyond the array.
Take into account that included by you header <stdio.h> is not used in the program. On the other hand you need to include header <cstdlib> that declares function system.
As for your second question then you should use for example standard container std::vector<std::string>
For example
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cstdlib>
int main()
{
std::ifstream file("p.txt");
std::string s;
std::vector<std::string> v;
v.reserve( 100 );
while ( file >> s ) v.push_back( s );
std::system( "pause" );
return 0;
}
Or you can simply define the vector as
std::vector<std::string> v( ( std::istream_iterator<std::string>( file ) ),
std::istream_iterator<std::string>() );
provided that you will include header <iterator>
For example
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <iterator>
#include <cstdlib>
int main()
{
std::ifstream file("p.txt");
std::vector<std::string> v( ( std::istream_iterator<std::string>( file ) ),
std::istream_iterator<std::string>() );
for ( const std::string &s : v ) std::cout << s << std::endl;
std::system( "pause" );
return 0;
}
Your code is invoking undefined behavior. That it doesn't crash is a roll of the dice, but its execution is not deterministic precisely because that is the nature of being undefined.
The easiest way (I've found) to load a file of words with whitespace separation is by:
std::ifstream inp("p.txt");
std::istream_iterator<std::string> inp_it(inp), inp_eof;
std::vector<std::string> strs(inp_it, inp_eof);
strs will contain every whitespace delimited char sequence as a linear vector of std::string. Use std::string for dynamic string content and don't feel the least bit guilty about exploiting the hell out of the hard work those that came before you gave us all: The Standard Library.
Your code is failing due to the overload of char * for operator>>.
An array of char, regardless the size, will decompose to the type char * where the value is the address of the start of the array.
For compatibility with the C language, the overloaded operator>>(char *) has been implemented to read one or more characters until a terminating whitespace character is reached, or there is an error with the stream.
If you declare an array of 1 character and read from a file containing "California", the function will put 'C' into the first location of the array and keep writing the remaining characters to the next locations in memory (regardless of what data type they are). This is known as a buffer overflow.
A much safer method is to read into a std::string or if you only want one character, use a char variable. Look in your favorite C++ reference for the getline methods. There is an overload for reading until a given delimiter is reached.
You only need a couple changes:
#include <cstring>
#include <fstream>
#include <stdio.h>
#include <string>
int main(){
ifstream file;
string word;
file.open("p.txt");
while (file >> word){
cout << word << endl;
}
system("pause");
return 0;
}
It works because you are lucky and you don't overwrite some critical memory. You need to allocate enough bytes for char word array, say char word[64]. And use while(file>>word) as your test for EOF. In the loop you can push_back the word into a std::vector<string> if you are allowed to use C++ STL.
If you want a simple C++11 STL-like solution, use this
#include <algorithm>
#include <iterator>
#include <vector>
#include <string>
#include <fstream>
#include <iostream>
using namespace std;
int main()
{
ifstream fin("./in.txt"); // input file
vector<string> words; // store the words in a vector
copy(istream_iterator<string>(fin),{}, back_inserter(words)); // insert the words
for(auto &elem: words)
cout << elem << endl; // display them
}
Or, more compactly, construct the container directly from the stream iterator like
vector<string> words(istream_iterator<string>(fin),{});
and remove the copy statement.
If instead a vector<string> you use a multiset<string> (#include <set>) and change
copy(istream_iterator<string>(fin),{}, back_inserter(words)); // insert the words
to
copy(istream_iterator<string>(fin),{}, inserter(words, words.begin())); // insert the words
you get the words ordered. So using STL is the cleanest approach in my opinion.
You're using C++, so you can avoid all that C stuff.
std::string word;
std::vector<std::string> words;
std::fstream stream("wordlist");
// this assumes one word (or phrase, with spaces, etc) per line...
while (std::getline(stream, word))
words.push_back(word);
or for multiple words (or phrases, with spaces, etc) per line separated by commas:
while (std::getline(stream, word, ','))
words.push_back(word);
or for multiple words per line separated by spaces:
while(stream >> word)
words.push_back(word);
No need to worry about buffer sizes or memory allocation or anything like that.
file>>char *
Will work with any char * and you are using
file >> word;
and it simply sees work variable as a char * but you are getting a segemntation fault somewhere and if your code grows you will see something is not working without any logical reason. GDB debugger will show you the seg fault

Parsing String to Array of Integers

I'm looking for a way to convert a string with specified dividers (such as slashes or spaces) into an array of the integers those dividers separate.
For example, if the user inputs 12/3/875/256, I need to retrieve the array {12, 3, 875, 256}. Ideally, it would be able to handle an arbitrary length.
I tried sweeping through the string character-by-character and storing everything that's not a divider in a temporary variable, which is added to the array the next time I encounter a divider character. Unfortunately, the type conversions are being a pain in the butt. Is there an easier way to do this?
You can set '/' to a delimiter and read using getline? then you'd have to put each one into a variable, and you'd need to know the size--maybe you can pass over the array and count the slashes? then you'd know that and can set up the array first. You might need to parse each string segment into an int, which may or may not be difficult. (haven't used c++ for a while, I don't remember a convenient way.)
See here for a small example of how this is done (3 posts down).
Try using the boost::tokenizer and boost::lexical_cast
strtok and strtol? (this is somewhat tongue in cheek. Strtok is usually not a good idea)
The splitting is covered in this Parsing String to Array of Integers
COnverting strings to int in C++ has quite a number of relevant questions https://stackoverflow.com/search?q=convert+string+to+int+c%2B%2B
What is the issue with the type conversions? It doesn't seem to be a block as far as I can see.
Can you show your code?
Take a look at this other answer. It even has an example of a tokenizer code using boost::tokenizer.
EDIT:
I copied the code there with the neccessary modifications:
#include <iostream>
#include <string>
#include <boost/foreach.hpp>
#include <boost/tokenizer.hpp>
#include <vector>
#include <boost/lexical_cast.hpp>
#include <iterator>
#include <algorithm>
using namespace std;
using namespace boost;
int main(int argc, char** argv)
{
string text = "125/55/66";
vector<int> vi;
char_separator<char> sep("/");
tokenizer<char_separator<char> > tokens(text, sep);
BOOST_FOREACH(string t, tokens)
{
vi.push_back(lexical_cast<int>(t));
}
copy(vi.begin(), vi.end(), ostream_iterator<int>(cout, "\n"));
}
Will print:
125
55
66
You could use a combination of Boost.split and Boost.lexical_cast to break up the string by whatever delimiters you want, and then you could lexical cast it all.
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <iostream>
#include <vector>
#include <string>
int main()
{
std::string s = "11/23/2010";
std::vector<std::string> svec;
std::vector<int> ivec;
// split the string 's' on '/' delimiter, and the resulting tokens
// will be in svec.
boost::split(svec, s, boost::is_any_of("/"));
// Simple conversion - iterate through the token vector svec
// and attempt a lexical cast on each string to int
BOOST_FOREACH(std::string item, svec)
{
try
{
int i = boost::lexical_cast<int>(item);
ivec.push_back(i);
}
catch (boost::bad_lexical_cast &ex)
{
std::cout << ex.what();
}
}
return 0;
}
Untested...don't have boost on this machine.
Other ways you could use to convert std::string/char * to int types involve stringstream use directly, or C constructs like atoi.