Equals returning false in c++ - c++

I'm fairly new to cpp and I am trying to do a project. It says that the code must take in a filename as an argument and will be run by:
./main -i filename
I have written a for-loop that will iterate through the list of arguments to find the "-i" argument so that I can determine the filename. But this line always return false:
argv[i] == "-i"
Below is my code:
#include <string>
#include <iostream>
int main(int argc, char *argv[]) {
std::string test = argv[0];
for(int i = 0; i < argc; i++){
if(argv[i] == "-i"){
test = argv[i+1];
break;
}
}
std::cout << test;
return 1;
}

argv[i] == "-i"
In the line above you compare two pointers: char* and const char*, respectively.
In other words, instead of comparing argv[i] and "-i" two pointers are compared which are pretty much unlikely to point to the same location. As a result, the check doesn't work in your case.
You can fix it in multiple ways, for example wrap "-i" into std::string to make the comparison work properly:
const auto arg = std::string{ "-i" };
for(int i = 0; i < argc; i++){
if(argv[i] == arg){
test = argv[i+1];
break;
}
}
Starting with C++17 you might also use a std::string_view:
const std::string_view sv{ "-i" };
for(int i = 0; i < argc; i++){
if(argv[i] == sv){
test = argv[i+1];
break;
}
}
which is a preferable way as it avoids a std::string creation.

You cannot compare pointers to char to string literals (char const*) using ==. Use std::strcmp() (<cstring>) or construct a std::string (<string>) from it to make it comparable to a char* using ==.

try this:
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char *argv[]) {
string test;
for(int i = 0; i < argc; i++){
cout << "\n" << argv[i] << endl;
if((string)argv[i] == "-i"){
test = argv[i + 1];
cout << "test= " << test << endl;
break;
}
}
cout << test << endl;
system("pause");
return 0;
}

Related

C++ - Checking if a word is palindrome in struct data type

I want to know how to check if a word is palindrome in struct data type or object whatever you want to call it. I want to read a data from file then I need to check if that type of word that I have read is a palindrome or not. Also i need to reverse order of the words but I did that so do not need any help about that.
Here is the code:
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
using namespace std;
struct lettersStr
{
string name;
string object;
};
int main(int argc, char** argv)
{
ifstream letter;
letter.open("letter.txt");
lettersStr things[200];
int numberOfThings= 0;
while(letter >> letter[numberOfThings].name >> letter[numberOfThings].object)
{
numberOfThings++;
}
for (int i = 0; i < numberOfThings; i++)
{
cout << letter[i].name << " " << letter[i].object<< endl;
}
string names;
for (int i = 0; i < numberOfThings; i++)
{
names= things[i].name;
}
for (int i = numberOfThings- 1; i >= 0; i--)
{
cout << things[i].name << endl;
}
bool x = true;
int j = names.length() - 1;
for (int i = 0; i < j; i++,j--)
{
if (things[i].name.at(i) != things[i].name.at(j))
x = false;
if (x)
{
cout << "String is a palindrome ";
}
else
cout << "String is not a palindrome";
}
And here is the cout:
Kayak Audi
Ahmed Golf7
Ahmed
Kayak
String is not a palindrome
String is not a palindrome
I think major problem is this:
for (int i = 0; i < j; i++,j--)
{
if (things[i].name.at(i) != things[i].name.at(j))
x = false;
As you can see it wont cout right way of checking if a word is palindrome or not.
P.S: If this is a stupid question I am sorry, I am a beginner in C++ programming.
Cheers
As already pointed out in the comments, for (int i = 0; i < j; i++,j--) loops though things and the letters of their names simultaneously. You also have to account for cases where you compare a lower and an upper case letter such as the 'K' and 'k' at the beginning and end of 'Kayak'. You can use std::tolower for this.
Here is an example (live demo):
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
#include <vector>
using namespace std;
bool is_palindrome(std::string name)
{
if (name.empty())
return false;
// As has been pointed out, you can also use std::equal.
// However, this is closer to your original approach.
for (unsigned int i = 0, j = name.length()-1; i < j; i++,j--)
{
if (std::tolower(name.at(i)) != std::tolower(name.at(j)))
return false;
}
return true;
}
struct lettersStr
{
string name;
string object;
};
int main(int argc, char** argv)
{
std::vector<lettersStr> vec = {lettersStr{"Kayak","Boat"},lettersStr{"Audi","Car"}};
for (const auto &obj : vec)
if (is_palindrome(obj.name))
std::cout << obj.name << " is a palindrome" << std::endl;
else
std::cout << obj.name << " isn't a palindrome" << std::endl;
}
It gives the output:
Kayak is a palindrome
Audi isn't a palindrome

C++ add checks to avoid reading two arguments

My code currently reads both arguments and i need to add a check for it to read 1 argument if someone put in one number such as 100 and to read the second argument if entered 100 3.
right now it reads both arguements everytime and and gives an error if one argument is entered.
#include <iostream>
#include <cstring>
using namespace std;
int perfectnumber(int number)
{
int sumofdivisor = 0;
for (int i = 1; i < number; i++)
{
if (number % i == 0)
sumofdivisor += i;
}
return abs(sumofdivisor - number);
}
int main(int argc, char *argv[])
{
int count = atoi(argv[2]);
int upper_limit = atoi(argv[1]);
for (int start = 2; start <= upper_limit; start++)
{
int difference = perfectnumber(start);
if (difference <= count)
{
cout << start << " ";
}
}
cout << endl;
}
The parameter argc is your friend, it tells you how many arguments there are.
Here is an example of how to use argc.
#include "stdio.h"
int main(int argc, char* argv[])
{
printf("Number: %d\n", argc);
printf("0: %s\n", argv[0]);
if (1<argc)
{
printf("1: %s\n", argv[1]);
}
}
You can use argc to see how many arguments are provided. The first argument is the name of the executable1, so you have to compare with 3. Here is a simple example:
#include <iostream>
#include <cstdlib>
int main(int argc, char *argv[])
{
if (argc < 3) {
std::cerr << "Too few arguments\n";
return EXIT_FAILURE;
}
std::cout << "Args: " << argv[1] << " and " << argv[2] << '\n';
}
1 This is not entirely correct. According to this reference: "argv[0] is the pointer to the initial character of a null-terminated multibyte string that represents the name used to invoke the program itself (or an empty string "" if this is not supported by the execution environment)." But as a comment points out, this is not entirely accurate either. This is a convention that implementations usually follow but are free to not to.

Taking parameters on the command line in C++

I've a program that takes two csv files and a checkin date as inputs and renders a certain output. Thus I'd normally run the executable in this manner,
./my_executable file.csv 2015-10-13
However my requirement is to have the usage behave this way
my_executable --input1 ./file1.csv --input2 ./file2.csv --date 2015-08-01
How can I do this. Do I have write the words input1, input2 and date somewhere in my code. Any help appreciated.
Simplest way I can think of:
Live On Coliru
#include <string>
#include <vector>
#include <iostream>
#include <iterator>
#include <cassert>
int main(int argc, char *raw_argv[]) {
using namespace std;
vector<string> const args { raw_argv+1, raw_argv+argc };
assert(args.size() < 1 || args[0] == "--input1");
assert(args.size() < 3 || args[2] == "--input2");
if (args.size() > 4) {
std::string const& csv1 = args[1];
std::string const& csv2 = args[3];
std::string date = args.size() > 4? args[4] : "(unspecified)";
std::cout << "Arguments received: " << csv1 << ", " << csv2 << " date:" << date << "\n";
}
}
Prints e.g.
./test --input1 stuff.csv --input2 other.csv
Arguments received: stuff.csv, other.csv date:(unspecified)
Command line arguments are passed to your program via the argument count and argument list parameters of main:
int main(int argument_count, char * argument_list[]);
The first parameter is the number of arguments, including the name of your executable.
The second argument is an array of C-style strings, one for each argument (or word) on the command line. The first item is usually the name of the program.
You can always write a small program to test this out:
#include <iostream>
int main(int arg_count, char * arg_list[])
{
for (unsigned int i = 0; i < arg_count; ++arg_count)
{
std::cout << "Argument " << i << ": " << arg_list[i] << std::endl;
}
return EXIT_SUCCESS;
}
Edit 1:
Your parameters would line up as:
Argument 0: my_executable
Argument 1: --input1
Argument 2: ./file1.csv
Argument 3: --input2
Argument 4: ./file2.csv
//...
If you want to compare these parameters, then yes, you would need to type "input1":
//...
std::string arg1 = arg_list[1];
if (arg1 == "--arg1")
{
//...
}
This should give you a kickstart.
https://www.gnu.org/software/libc/manual/html_node/Argp-Example-3.html#Argp-Example-3
or if you want to handle the arguments manually.
see: https://www.gnu.org/software/libc/manual/html_node/Program-Arguments.html#Program-Arguments
int main(int argc, const char **argv[])
{
for(int i = 0; i < argc; i++) {
std::cout << argv[i] << std::endl;
}
return 0;
}
Usually when you give argument in that way the order should not matter, so you'll have to be able to parse the arguments in any order.
Here is a possible solution:
struct arguments
{
std::string input1;
std::string input2;
std::string date;
};
bool parse_arguments(int argc, char** argv, arguments& args)
{
if(argc < 7){ //or set defaults
//print usage();//implement
return false;
}
for(int i=1; i<argc;i+=2){
string command = argv[i];
string argument = argv[i+1];
if(command == "--input1"){
args.input1 = argument;
}
else if(command == "--input2"){
args.input2 = argument;
}
else if(command == "--date"){
args.date = argument;
}
else{
std::cerr<<"Unknown argument: " <<command<<std::endl;
//print usage();
return false;
}
}
if(args.input1.empty() || args.input2.empty() || args.data.empty())
return false;
return true;
}
int main(int argc, char* argv[]){
arguments args;
parse_arguments(argc,argv, args);
//now you can use the struct.
...
}

Modify contents of string literal C++ based on function constraints

I need to convert a given string literal to its lower case by passing the string as an argument to the function Lower(char *). The function can return only int.
In the main() i need the converted string to be accessible somehow.
Currently i am type casting the address of the tmp string in the Lower() function and then trying to dereference that address.
This is the code:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int Lower(char* str)
{
char tmp[100];
for(int i=0;i<=strlen(str);i++)
{
if(isupper(*(str+i)))
*(tmp+i) = *(str+i)+32;
else
*(tmp+i) = *(str+i);
}
return int(tmp);
}
int main()
{
char* str = "gOAt";
char *rc=(char *)Lower(str);
printf(rc);
return 0;
}
Again the function prototype cannot change ie the prototype must be int Lower(char *). However, "goat" must be somehow accessible in the main() function. How can this be done?
There are multiple things wrong with the posted code. My take would be that the int returned from the function is a status code, when it's 1, it signals that the conversion to lowercase was successful, 0 otherwise. Here is a working program that does the conversion:
#include <iostream>
using namespace std;
int lower(char* str)
{
int hasLower = 0;
while(*str)
{
if (*str >= 'A' && *str <= 'Z')
{
*str = (*str - 'A') + 'a';
hasLower = 1;
}
str++;
}
return hasLower;
}
int main(int argc, char** argv)
{
if (argc != 2) { cout << "No input! Exiting..." << endl; return 1; }
char* input = argv[1];
if (lower(input))
{
cout << "Lower case: " << input << endl;
}
else
{
cout << input << " isn't a valid string for lower-case conversion" << endl;
}
return 0;
}

How to output an integer value in command line argument to characters of the equivalent length as the value in C++?

I got a value say 10 and i want to output this into xxxxxxxxxx (10 x). How do i do this?
The value 10 is passed in via the command line.
I have tried this, but it doesn't do what I want:
for (i = 1; i < argc; i++){
cout << argv[i++] << " " << argv[i] << endl;
} // i cant get the argv[i] to print out the value in 'x'
if (argc>1)
cout << string(atoi(argv[1]), 'x');
There is a way using the streams, but I don't know it offhand: it's something like cout.SetPrecision(). But the C way is to provide a format specification.
int
main (int argc, char **argv)
{
printf ("%*d\n", atoi(argv[1]), 10); // outputs 10 into fieldwidth given by parameter
}
This needs quite a bit of development to handle pathologies of input, but the basic concept works. * means use the next parameter as a field width.
You simply need
std::cout << std::string(10, 'x');
So fullblown:
#include <iostream>
#include <string>
#include <sstream>
int main(int argc, const char* args[])
{
if (argc>1)
{
std::istringstream iss(args[1]);
unsigned long i = 0;
iss >> i;
std::cout << std::string(i, 'x');
}
return 0;
}
See here