how to operate on global variables in c++ - c++

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.

Related

A way around creating a std::string that stores different types

So I have a function that takes in a void* which is then casted to uint8* and then populated. In the caller code, it's then appended to std::string. Sort of like in the example below.
But I want to make it generic such that I could store different types into string without hardcoding for specific type in the caller code. For e.g: if I were to store 0x5 in a char array, I'd have to use to_string() as shown below. However if I have to store a char itself, I wouldn't have to use to_string().
void foo(void *p) {
uint8_t *ptr = reinterpret_cast<uint8_t*>(p);
*ptr = 0x5; // for e.g
// now ptr stores a char. th
*ptr = 'C';
}
int main(void) {
char arr[20] = {0};
std::string str;
foo(arr);
for (int i=0; i<20; i++) {
str += to_string(arr[i]);
}
cout << str; //
}
Here's a sample code: https://cplayground.com/?p=jackal-cormorant-koala
you can see how it doesn't print when an integer is stored mainly cause I didn't use to_string(). I'm just looking to have a generic function that stores the value as it is. If 15 is stored in a char array, string stores "15". If 'A' is stored in a char array, string stores "A"
Although comments about serialization are the way to go, if you only want to create a string with char and int you can overload a function.
std::string store(int n) {
return std::to_string(n);
}
std::string store(char c) {
std::string s;
s += c;
return std::string(s);
}
int main(void) {
//char arr[5] = {0};
std::string str = store(15);
cout << "String: " << str << endl;
// ----------------------------------
str += store('A');
cout << "String: " << str << endl;
//populateString(arr);
}
Output:
String: 15
String: 15A

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.

argc, argv implementation c++

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.

c++ error: change from command line input to variable input

I want to change from command line input to variable input.
int main(int argc, char *argv[])
{
std::cout << argc << std::endl;
std::cout << argv[0] << std::endl;
std::cout << argv[1] << std::endl;
}
Change to this, but when I want to compile this an error appears.
int main()
{
int argc = 2;
char *argv[] = 0;
argv[0] = "./server";
argv[1] = "127.0.0.1";
}
This error appears: error: array initializer must be an initializer list
char *argv[] = 0;
You have to provide the size of the array, since you did not provide an initializer from which the compiler can deduce the size. Again, from C++11 you cannot have a string-literal bind to char*, use const char*.
int main()
{
constexpr int argc = 2;
const char *argv[argc] = {};
argv[0] = "./server";
argv[1] = "127.0.0.1";
}
You may want to explore good use of std::array<std::string, 2> instead.

Comparing std::string with constants vs comparing char arrays with constants In C++

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.