All I want to do for right now is sort command-line arguments, but I keep getting a segmentation fault (core dumped) error, which I think means I have a pointer pointing at an imaginary place.
#include<iostream>
#include<cstdlib>
#include<algorithm>
#include<vector>
using namespace std;
int main (int argc, char* argv[]) {
vector<int> the_args;
vector<int>::iterator it;
it = the_args.begin(); //this seems logical to me.
int i = 1; //so I'll skip over argv[0]
while (i < argc)
{
the_args.insert (it, atoi(argv[i]));
i++;
it++;//this is probably the perpetrator.
}
sort (the_args.begin(), the_args.end());
for (it = the_args.begin(); it < the_args.end(); it++) //or else it's this
{
cout << *it << " ";
}
return 0;
}
I eventually want to program games. I've got enough experience in Java that I figured I could start trying to screw around in C++ and figure it out... but maybe not? Please be nice in your answers, I'm really discouraged that I even have to ask a question on here about sorting something.
Here:
vector<string> the_args( argv + 1, argv + argc );
Or:
vector<int> the_args;
for( int i = 1; i < argc; ++i )
{
the_args.push_back( atoi( argv[i] ) );
}
Then just sort it with std::sort as you’re doing.
the_args.insert (it, atoi(argv[i]));
This invalidates it. Scrap the iterator, and just use push_back.
the_args.push_back(atoi(argv[i]));
Alternatively, insert returns a valid iterator to the object that was just inserted, so you could also do this:
it = the_args.insert (it, atoi(argv[i]));
But that's unnecessarily complicated if you are just inserting at the end of the vector. Here's an option which replaces your entire loop, if you're a fan of one-liners:
std::transform(argv + 1, argv + argc, std::back_inserter(the_args), std::atoi);
Try the following
#include<iostream>
#include<cstdlib>
#include<vector>
int main (int argc, char* argv[])
{
vector<int> the_args
if ( argc > 1 ) the_args.reserve( argc - 1 );
for ( int i = 1; i < argc; i++ ) the_args.push_back( std::atoi( argv[i] ) );
std::sort( the_args.begin(), the_args.end() );
for ( int x : the_args )
{
std::cout << x << " ";
}
std::cout << std::endl;
return 0;
}
Related
I wanna sort an array of command line arguments. All arguments are integer.
Here is my code, but it does not work.
#include <iostream>
using namespace std;
int main (int argc, char *argv[]) {
for (int i=0; i<argc-1; ++i) {
int pos = i;
for (int j=i+1; j<argc; ++j) {
if (argv[j] - '0' < argv[pos] - '0') {
pos = j;
}
}
char *tempt = argv[i];
argv[i] = argv[pos];
argv[pos] = tempt;
}
for (int i=0; i<argc; ++i) {
cout << argv[i] <<endl;
}
}
After compiling, when I called ./a.out 4 3 2 1, it still printed 4 3 2 1 to the screen instead of 1 2 3 4.
What's wrong?
Thanks in advance.
Try std::sort from <algorithm> with a custom comparator
std::sort(argv, argv + argc, [](char * const & a, char * const & b) {
return atoi(a) < atoi(b);
});
In modern c++ you can use auto types for lambdas. For string to int convertion I would prefer stoi function over atoi (you can look for differences here). Also worth noting that first argument (argv[0]) is a program name, e.g. ./a.out, so you need to skip it from sorting. Final result could be looks like this:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
int main (int argc, char *argv[]) {
std::sort(argv + 1, argv + argc, [](auto l, auto r){ return std::stoi(l) < std::stoi(r); } );
std::copy(argv + 1, argv + argc, std::ostream_iterator<const char*>(std::cout, " "));
}
If all of command line arguments a unsigned number with fixed digits count you could also sort them like string, i.e. without explicit converting to numbers via std::stoi. In this case std::vector<std::string> could be used:
std::vector<std::string> v(argv + 1, argv + argc);
std::sort(v.begin(), v.end());
There is no need to use lambda or another custom comparator for std::sort.
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.
im creating a hangman game that has to use CHAR and not strings. I was wondering how i would choose a single random word form a Char array and display it to the console as a symbol e.g. ****** instead of the word. My current array; Thank you.
char words [6][10] =
{
"Pistachio",
"Avocado",
"Salami",
"Bologna",
"Christmas",
"Giraffes",
};
This is what i have so far (i know it not much im a bit confused)
cout <<"Test " <<words <<endl;
and that just out put a random number ??
To output a cstring from an array of cstrings you need to provide the index of that string.
cout <<"Test " <<words <<endl;
Will just print the address of the first element of the array since that is what an array name is reduced to. So the correct way to display from the array is:
cout <<"Test " <<words[indexOfTheStringYouWant] <<endl;
words is a char** an array of char[10]. The << operator knows how to print simple types (int, float), std::string and char *, but not char ** arrays nor pointers to C strings (char arrays). So it only print the address of the array of char *. char[10]
I think that what you want is :
for (int i=0; i< sizeof(words)/sizeof(char *); i++) cout << words[i] << " ";
cout << endl;
If I have understood correctly what you need is the following
#include <iostream>
#include <algorithm>
#include <numeric>
#include <cstdlib>
#include <ctime>
int main()
{
const size_t N = 6;
const size_t M = 10;
char words[N][M] =
{
"Pistachio",
"Avocado",
"Salami",
"Bologna",
"Christmas",
"Giraffes",
};
size_t index[N];
std::iota( index, index + N, 0 );
std::srand( ( unsigned int )std::time( nullptr ) );
std::random_shuffle( index, index + N );
for ( size_t i = 0; i < N; i++ ) std::cout << words[index[i]] << std::endl;
return 0;
}
The program output might look like
Giraffes
Bologna
Pistachio
Avocado
Salami
Christmas
I think you are looking for this:
#include<cstdlib>
int v;
for(int i=0; i<10; i++)
{
v = rand() %6;
printf("%s\n", words[v]);
}
i am trying to use command line argument in Linux(Ubuntu) in c++ . but it generates run time error : segmentation fault.this program runs with no error in windows .here is my code
#include<iostream>
using namespace std;
int main(int argc , char **argv){
char **ss;
for(int i=0;i<argc;i++){
ss[i] = argv[i];
}
for(int i=0;i<argc ;i++)
cout<<ss[i];
return 0;
}
what is wrong with this code. please help me . thanks in advance.
Your program has undefined behaviour because you did not initialize pointer ss and allocate memory where you are going to copy elements pointed by argv
char **ss; // What value does it have?
for(int i=0;i<argc;i++){
ss[i] = argv[i];
You could do the following way
char **ss = new char *[argc];
for(int i=0;i<argc;i++){
ss[i] = argv[i];
The better way is to use std::vector<std::string>. In this case you could also copy not only pointers to arguments but and also the arguments. For example
#include<iostream>
#include <vector>
#include <string>
int main(int argc , char **argv)
{
std::vector<std::string> v( argv, argv + argc );
for ( const std::string &s : v ) std::cout << s << std::endl;
return 0;
}
If your compiler does not support the range based for statement then you can substitute it for
for ( std::vector<std::string>::size_type i = 0; i < v.size(); i++ )
{
std::cout << v[i] << std::endl;
}
As already answered, you haven't allocated any memory for ss.
Since you're using c++ and not c, you should have the c++ standard library at your disposal:
std::vector<std::string> ss;
ss.reserve(argc); // not necessary
for(int i=0;i<argc;i++)
ss.push_back(argv[i]);
Use the following declaration for ss
#include<iostream>
using namespace std;
int main(int argc , char **argv){
char *ss[argc]; // <--allocate argc count of pointers
for(int i=0;i<argc;i++){
ss[i] = argv[i];
}
for(int i=0;i<argc ;i++)
cout<<ss[i];
return 0;
}
I need to loop in a circular way over a container, such that for every iteration, I have access to a current and the previous element. For the first iteration, the previous element should be the back element of a container.
This example is doing that:
#include <vector>
#include <iostream>
using namespace std;
int main(int argc, const char *argv[])
{
vector<int> v = {0,1,2,3,4,5,6};
auto xPreviousIt = v.end();
--xPreviousIt;
int i = 0;
for (auto xCurrent : v)
{
cout << xCurrent << " " << *xPreviousIt << endl;
xPreviousIt = v.begin() + i;
++i;
}
return 0;
}
but I want to know if there is a better way of achieving something like this? Like a circular iterator that starts at the begining of a container and ends there as well? All I could find in boost was the circular buffer.
It is simpler to use an ordinary for loop. If for example init is a starting index then you could write
for ( std::vector<int>::size_type i = 0; i < v.size(); i++ )
{
std::cout << v[( init + i ) % v.size()] << ' ';
}
std::cout << std::endl;