I have a problem with my main part of the program. I am trying to implement the arguments in main with argc, argv that will receive as input txt files. Also when I try to read the files I receive an error like : Variable i is used without being initialised and I must click Abort.
The main part of the code is this one:
void main(int argc, char* argv[])
{
cout <<"<---------------FAZA 2--------------->" <<endl;
cout << " Numar de argumente ale functiei main:" << argc << endl;
for (int i = 0; i < argc; i++)
{
if (argv[i] = "Angajat.txt")
{
Fisiere_Intrare f1;
f1.Fisiere_Angajati();
break;
}
else
cout << " O.K." << endl;
}
Fisiere Intrare is a class written like this:
class Fisiere_Intrare
{
public:
void Fisiere_Angajati()
{
ifstream fis;
fis.open("Angajat.txt", ifstream::in);
if (fis.is_open())
{
while (!fis.eof())
{
Angajat a;
fis >> a;
cout << a;
}
}
fis.close();
}
};
"Angajat" is also a class with the following atributes: name, salary, work_age.
There are several problems in your code:
if (argv[i] = "Angajat.txt")
As KeithSmith pointed out "=" is the assignment operator, for comparisons the "==" operator would be needed.
Additionally C-Strings cannot be compared that easily in C/C++. As you tagged your question with c++, you could convert your argument into a std::string object and compare this with your filename:
if (std::string(argv[i]) == "Angajat.txt")
However, the error message you mentioned suggests that there might be another problem hidden somewhere.
The argv[] is const char* and i is undetermined, which cannot be figured out by the complier.
Related
I need help with global vars in C++. I am passing an empty argv array into a parse function and I am trying to fill it, however when I access argv back in main, argv[0] comes back empty no matter what I enter in. Please help.
static int argc;
static char* argv[100];
void parse(string str, int argc, char* argv[])
{
argc = 0;
char * cstr = new char [str.length()+1];
strcpy (cstr, str.c_str());
char * p = strtok (cstr," ");
int i = 0;
while (p!=0)
{
argc++;
argv[i] = p;
p = strtok(NULL," ");
i++;
}
delete[] cstr;
}
int main( void )
{
string theLine;
while (true)
{
cout << "myshell> ";
getline(cin,theLine);
cout << "Command was: " << theLine << endl;
if ((theLine == "exit") || (cin.eof()) || (theLine == "quit"))
exit(0);
parse(theLine, argc, argv);
cout << "argv[0] " << argv[0] << "\n";
}
}
I am trying to assign character strings to argv inside the parser function but when I go to access it in MAIN, it comes out blank. How do I achieve what I am trying to do? It has to do with global variables but I cannot figure out how.
The problem is that you're storing pointers into cstr in argv, but then you're deleting cstr at the end of the parse() function. Get rid of:
delete[] cstr;
Also, you should pass argc by reference. Otherwise, when you update it in the parse() function it won't update the caller's variable. So it should be:
void parse(string str, int &argc, char *argv[])
However, you also have a memory leak. You're creating a new cstr each time parse is called, but never deleting it. You should change the function to return cstr, and have the caller delete it when they're done with that parsed line.
char *parse(str str, int &argv, char *argv[]) {
...
return cstr;
}
Then in your main() loop, do:
int main( void )
{
string theLine;
while (true)
{
cout << "myshell> ";
getline(cin,theLine);
cout << "Command was: " << theLine << endl;
if ((theLine == "exit") || (cin.eof()) || (theLine == "quit"))
exit(0);
char *cstr = parse(theLine, argc, argv);
cout << "argv[0] " << argv[0] << "\n";
delete[] cstr;
}
}
You are confused about how global and local variables of the same name interact.
Let me start by saying that there are two distinct objects each named argc and two distinct objects each named argv.
The first set are the global variables
static int argc;
static char* argv[100];
The second set are the parameters of your parse function
void parse(string str, int argc, char* argv[])
{
argc = 0;
...
}
I've taken one line from parse. What that does is actually set the object in the argc parameter to 0. The object in the global argc is not set to 0 by this.
Let's rename some of the variables in the above snippet to see clearly which name belongs to which object/place:
static int global_argc;
static char* global_argv[100];
void parse(string str, int argc, char* argv[])
{
argc = 0;
...
}
Now, notice how I changed the first two to global_, but the rest (all of the, even the ones not shown) remain argc and argv.
You need to start by learning about variable scope. Once arrays and pointers are involved, such as argv, things get even more complicated. I could not possibly explain all of this to you in one answer, except for: first learn more about variables and variable scope. Then learn about pointers and arrays. Then come back to this program and see if you can fix it, which is not something you can do at this point in time.
It may take a little more time, and a little more work, but don't get discouraged.
I need to get an argument and convert it to an int. Here is my code so far:
#include <iostream>
using namespace std;
int main(int argc,int argvx[]) {
int i=1;
int answer = 23;
int temp;
// decode arguments
if(argc < 2) {
printf("You must provide at least one argument\n");
exit(0);
}
// Convert it to an int here
}
Since this answer was somehow accepted and thus will appear at the top, although it's not the best, I've improved it based on the other answers and the comments.
The C way; simplest, but will treat any invalid number as 0:
#include <cstdlib>
int x = atoi(argv[1]);
The C way with input checking:
#include <cstdlib>
errno = 0;
char *endptr;
long int x = strtol(argv[1], &endptr, 10);
if (endptr == argv[1]) {
std::cerr << "Invalid number: " << argv[1] << '\n';
} else if (*endptr) {
std::cerr << "Trailing characters after number: " << argv[1] << '\n';
} else if (errno == ERANGE) {
std::cerr << "Number out of range: " << argv[1] << '\n';
}
The C++ iostreams way with input checking:
#include <sstream>
std::istringstream ss(argv[1]);
int x;
if (!(ss >> x)) {
std::cerr << "Invalid number: " << argv[1] << '\n';
} else if (!ss.eof()) {
std::cerr << "Trailing characters after number: " << argv[1] << '\n';
}
Alternative C++ way since C++11:
#include <stdexcept>
#include <string>
std::string arg = argv[1];
try {
std::size_t pos;
int x = std::stoi(arg, &pos);
if (pos < arg.size()) {
std::cerr << "Trailing characters after number: " << arg << '\n';
}
} catch (std::invalid_argument const &ex) {
std::cerr << "Invalid number: " << arg << '\n';
} catch (std::out_of_range const &ex) {
std::cerr << "Number out of range: " << arg << '\n';
}
All four variants assume that argc >= 2. All accept leading whitespace; check isspace(argv[1][0]) if you don't want that. All except atoi reject trailing whitespace.
Note that your main arguments are not correct. The standard form should be:
int main(int argc, char *argv[])
or equivalently:
int main(int argc, char **argv)
There are many ways to achieve the conversion. This is one approach:
#include <sstream>
int main(int argc, char *argv[])
{
if (argc >= 2)
{
std::istringstream iss( argv[1] );
int val;
if (iss >> val)
{
// Conversion successful
}
}
return 0;
}
std::stoi from string could also be used.
#include <string>
using namespace std;
int main (int argc, char** argv)
{
if (argc >= 2)
{
int val = stoi(argv[1]);
// ...
}
return 0;
}
As WhirlWind has pointed out, the recommendations to use atoi aren't really very good. atoi has no way to indicate an error, so you get the same return from atoi("0"); as you do from atoi("abc");. The first is clearly meaningful, but the second is a clear error.
He also recommended strtol, which is perfectly fine, if a little bit clumsy. Another possibility would be to use sscanf, something like:
if (1==sscanf(argv[1], "%d", &temp))
// successful conversion
else
// couldn't convert input
note that strtol does give slightly more detailed results though -- in particular, if you got an argument like 123abc, the sscanf call would simply say it had converted a number (123), whereas strtol would not only tel you it had converted the number, but also a pointer to the a (i.e., the beginning of the part it could not convert to a number).
Since you're using C++, you could also consider using boost::lexical_cast. This is almost as simple to use as atoi, but also provides (roughly) the same level of detail in reporting errors as strtol. The biggest expense is that it can throw exceptions, so to use it your code has to be exception-safe. If you're writing C++, you should do that anyway, but it kind of forces the issue.
Take a look at strtol(), if you're using the C standard library.
The approach with istringstream can be improved in order to check that no other characters have been inserted after the expected argument:
#include <sstream>
int main(int argc, char *argv[])
{
if (argc >= 2)
{
std::istringstream iss( argv[1] );
int val;
if ((iss >> val) && iss.eof()) // Check eofbit
{
// Conversion successful
}
}
return 0;
}
Like that we can do....
int main(int argc, char *argv[]) {
int a, b, c;
*// Converting string type to integer type
// using function "atoi( argument)"*
a = atoi(argv[1]);
b = atoi(argv[2]);
c = atoi(argv[3]);
}
In my opinion this is the most practical way to pass your variables. Using std::stoi. It's good practice to use std:: and NOT to use namespace; this is why I can define a string with "string" as the variable name
#include <iostream>
#include <string>
int main(int argc, char **argv)
{
std::string string{argv[1]};
int integer1{std::stoi(argv[2])};
int integer2{std::stoi(argv[3])};
int sum{integer1 + integer2};
std::cout << string << " sum " << sum;
}
Example:
./out this 40 1 // input
this sum 41 // output
I'm writing a program which needs to read input from cin into a string. When I tried using the regular getline(cin, str) it endlessly prompted for input and never moved on the the next line of code. So I looked in my textbook and it said I could pass a cstring and size of the string to getline in the form of cin.getline(str, SIZE). However, when I do that I get the error "no instance of overloaded function getline matches the argument list.
I searched around, but all I found was people saying to use the getline(cin,str) form which led to the infinite input prompt, or the suggestion that there might be two different getline functions with different parameters in the classes I'm including, and that I need to tell the IDE to use the correct one(I'm not sure how to do that).
This is what I include at the beginning of my file:
#include <string>
#include <array>
#include <iostream>
#include "stdlib.h"
#include "Bank.h" //my own class
using namespace std;
And this is the relevant section of code:
const int SIZE = 30; //holds size of cName array
char* cName[SIZE]; //holds account name as a cstring (I originally used a string object in the getline(cin, strObj) format, so that wasn't the issue)
double balance; //holds account balance
cout << endl << "Enter an account number: ";
cin >> num; //(This prompt works correctly)
cout << endl << "Enter a name for the account: ";
cin.ignore(std::numeric_limits<std::streamsize>::max()); //clears cin's buffer so getline() does not get skipped (This also works correctly)
cin.getline(cName, SIZE); //name can be no more than 30 characters long (The error shows at the period between cin and getline)
I'm using Visual Studio C++ 2012, if that's relevant
This is the offending line:
char* cName[SIZE];
What you really need here is:
char cName[SIZE];
Then, you should be able to use:
cin.getline(cName, SIZE);
This error message from visual studio is quite misleading. Actually for me I was trying to call a non const member function from const member function.
class someClass {
public:
void LogError ( char *ptr ) {
ptr = "Some garbage";
}
void someFunction ( char *ptr ) const {
LogError ( ptr );
}
};
int main ()
{
someClass obj;
return 0;
}
Related to the answer of R Sahu the compiler gives a clue that the argument does not match.
Try the following code which does not give the error and makes the error message more clear.
#include <iostream>
class someClass {
public:
void LogError(char* ptr) {
std::cout << "LogError: before arg=" << ptr << "\n";
ptr[0] = 0;
std::cout << "LogError: after arg=" << ptr << "\n";
}
void LogError(char* ptr) const {
std::cout << "const LogError: arg=" << ptr << "\n";
}
void ROFunction(char* ptr) const {
LogError(ptr);
}
void RWFunction(char* ptr) {
LogError(ptr);
}
};
int main()
{
char s[] = "test";
someClass obj;
obj.ROFunction(s);
obj.RWFunction(s);
obj.ROFunction(s);
return 0;
}
With the output:
const LogError: arg=test
LogError: before arg=test
LogError: after arg=
const LogError: arg=
I figured this question had been asked a million times but I can't find the answer anywhere. Should be simple. Ok so I have a struct in my .h file:
struct question{
string programNum;
string programDesc;
string programPoints;
string programInput;
char programQuestion;
};
And then I have function initiated in the .h and arguments in .cpp:
void setQuestionFileName(question q, char fileName){
q.programQuestion = fileName;
}
Ok all is well so far. Now in main I have the issue of trying to store argv[1] in programQuestion:
char* fileName = argv[count+1];
followed by:
setQuestionFileName(questions[count],fileName);
cout << questions[count].programQuestion << endl;
I'm not real good with pointers so if anyone could help me store the char* argv into the char questions[count].programQuestion that would be amazing. Thank you!
I'm going to post the code, I think it may work better that way. This is the .h:
using namespace std;
// Data
struct question{
string programNum;
string programDesc;
string programPoints;
string programInput;
char* programQuestion;
};
void setQuestionFileName(question* q, char* fileName);
void display(question* q);
void display(question* q);
This is the .cpp
using namespace std;
void setQuestionFileName(question* q, char* fileName){
strcpy(q->programQuestion, fileName);
}
void display(question* q){
cout << "Description = " << q->programDesc << endl;
cout << "Number of Points = " << q->programPoints << endl;
cout << "Name of Question File = " << q->programQuestion << endl;
}
// Not used or tested yet
int myCompare (const void * a, const void * b ) {
const char *pa = *(const char**)a;
const char *pb = *(const char**)b;
return strcmp(pa,pb);
}
And main.cpp:
using namespace std;
int main(int argc, char* argv[]){ //or char** argv
question* questions[argc-1]; //Array of questions to be filled by loop.
int sizeOfQuestions = argc; //number of questions passed in at run time
int numLines = 0; //number of lines in file
for(int i=0;i<argc;i++){ //Test loop to make sure the command line file names are read in
std::cout << argv[i] << " says hello" << std::endl;
}
for(int count=0;count<sizeOfQuestions-1;count++){ //This loop places the information from the files into structs
//char fileName = argv[count+1];
char* fileName = argv[count+1];
cout << "Problem number: " << count+1 << "\t Working with file " << fileName << endl;
std::fstream questionFile (fileName, std::fstream::in); //Open the file
if(questionFile.good()){
cout << "File Opened" << endl;
setQuestionFileName(questions[count],fileName);
cout << questions[count]->programQuestion << endl;
getline(questionFile,questions[count]->programNum);
getline(questionFile,questions[count]->programDesc);
getline(questionFile,questions[count]->programPoints);
getline(questionFile,questions[count]->programInput);
display(questions[count]);
questionFile.close();
}else{
cout << "Could not open file!!!" << endl;
}
}
return 0;
}
The way it is now, I'm getting a segmentation fault.
Change your programQuestion from char to char*
And, this function
void setQuestionFileName(question q, char fileName){
q.programQuestion = fileName;
}
I think it should be
void setQuestionFileName(question& q, char* fileName){
strcpy(q.programQuestion, fileName);
}
Hardly there is a file with only 1-character name.
I am trying to make a little text adventure to get a handle on C++.
cin >> keyboard1;
if ((keyboard1 == "inv")inventory(inv);
This will work if keyboard1 is a string, but won't if it's a char array, is this because I haven't included the null at the end of the constant?
Let'say your code is the following:
int main(int argc, char *argv[])
{
std::string s;
std::cin >> s;
std::cout << s << std::endl;
if (s == "inv") {
std::cout << "Got it" << std::endl;
}
return 0;
}
This works as expected because of the way the stl class string overrides the == operator.
You cannot expect the following code to work instead:
int main(int argc, char *argv[])
{
char *s = (char *)calloc(10, sizeof(char));
std::cin >> s;
std::cout << s << std::endl;
if (s == "inv") {
std::cout << "Got it" << std::endl;
}
return 0;
}
because you are comparing s, which is the address where the string starts to a constant string (which, by the way, is automatically null-terminated by the compiler).
You should use strcmp to compare "c-strings":
int main(int argc, char *argv[])
{
char *s = (char *)calloc(10, sizeof(char));
std::cin >> s;
std::cout << s << std::endl;
if (strcmp(s, "inv") == 0) {
std::cout << "Got it" << std::endl;
}
return 0;
}
This works.
No, the reason it won't work is because you will be comparing the address of the memory that represents each string. Use strcmp / wcscmp instead.
The reason why comparing a string and a constant work is because the string class will have an equality operator defined (e.g. bool StringClass:operator==(const char* pszString)).
If keyboard1 is a char array, then if (keyboard1 == "inv") is performing a simple pointer comparison (both become char*).
When keyboard1 is a string, it can call an operator==(cosnt string&, const char*) if one exists, otherwise, if the string has the non-explicit constructor string(const char *s), the constant "inv" would be implicitly converted to a string object, and operator==(const string&,const string&) applied.