0

I am currently working on a class that stores strings. It is supposed to have two seperate constructors, one allowing the user to initialize the object with argv type of arguments, while the other initializes the object with environ type of arguments.

Everything works perfectly when I am using argv, the object is correctly initialized and stores every string I added in the command line. However, for the environ variables I run into trouble. Storing every environ string into my object seems to ambitious, as it exceeds the memory I have access to.

Are there any ways to reduce the size of the environ variable, or control the amount of variables main takes as an argument?

Fyi, the class containt two data members: one storing the amount of strings stored, while the other is the actual array of strings. I tried using a dynamically allocated array, using the amount of environ variables as an argument (counted using a for loop). However, there appear to be too many variables hence I end up with a bad_alloc error.

Stringstore::Stringstore(char ** envp)
{  
    for (char** env = envp; *envp != nullptr; ++env)
        ++d_size;
    d_str = new string[d_size];
    for (int index=0; index != d_size; ++index)
        d_str[index] = envp[index];
} 

class Stringstore
{
string *d_str;
int d_size;
public:
    Stringstore(int argc, char **argv1);
    Stringstore(char **envp);
};


int main(int argc, char **argv, char **envp)
{
    Stringstore(envp);    
}
  • maybe you could post some [mcve] ? On a modern computer I'm surprised you cannot copy some env. variables. – Jean-François Fabre Oct 12 '16 at 18:33
  • I have added the core code I currently have to initialize an object using environ variables. – Blackjaguar Oct 12 '16 at 18:45
  • What are the symptoms of the error, would it by chance be an infinite loop? (and assuming a memory error would be wrong) – Jean-François Fabre Oct 12 '16 at 19:07
  • Actually, the error occurs when I try to dynamically allocate the array with the calculated size. Whenever I ask the user to input the amount of environ variables to store, the program executes well. Perhaps it is simply too much for my current memory to store every single environ variable. – Blackjaguar Oct 12 '16 at 19:11

1 Answers1

1

This loop you use to count how many env. vars you receive is an infinite loop. envp does not change from one iteration to another.

for (char** env = envp; *envp != nullptr; ++env)
        ++d_size;

Since envp is not nullptr at the start, you never reach the exit condition which makes you believe that you're running out memory but no: you're running out of CPU :)

Another error: in the main you should build an object not try to "cast" to Stringstore:

int main(int argc, char **argv, char **envp)
{
    Stringstore the_string_store(envp);    
}

Note that using a vector (auto-realloc, no new, trivial copy-constructor for your class) would maybe have avoided that error. Let me propose a fixed code (which prints the env in the end to prove it works)

#include <string>
#include <vector>
#include <iostream>

using namespace std;

class Stringstore
{
std::vector<string> d_str;
public:
    Stringstore(int argc, char **argv1);
    Stringstore(char **envp);
};
Stringstore::Stringstore(char ** envp)
{  
    // store each env. string
    for (; *envp != nullptr; ++envp)
        d_str.push_back(*envp);

   // debug: print the contents of the vector
   for (auto it : d_str)
   {
      cout << it << endl;
   }
} 


int main(int argc, char **argv, char **envp)
{
    Stringstore s(envp);    
}

Running this I get this:

ALLUSERSPROFILE=C:\ProgramData
APPDATA=D:\Users\xxxxxxx\AppData\Roaming
CommonProgramFiles=C:\Program Files (x86)\Common Files
CommonProgramFiles(x86)=C:\Program Files (x86)\Common Files
CommonProgramW6432=C:\Program Files\Common Files
COMPUTERNAME=xxxxxx
...

Last edit: if you're not allowed to use vector, well that's a bummer, however this fixed version of your method works fine:

Stringstore::Stringstore(char ** envp)
{  
    // make a copy so we can count and preserve the original pointer
    // for the second pass: the string copy
    char **envp_copy = envp;  
    d_size = 0;  // you forgot to initialize it too :)

    for (; *envp_copy != nullptr; ++envp_copy)
        d_size++;  // count

    // the rest is your code, unchanged
    d_str = new string[d_size];
    for (int index=0; index != d_size; ++index)
        d_str[index] = envp[index];

    // debug: print env
    for (int index=0; index != d_size; ++index)
    {
        cout << d_str[index] << endl;
    }

}
Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
  • Thanks for your reply! – Blackjaguar Oct 12 '16 at 19:16
  • Thanks for your reply! The cast is actually a type. Do you have any other suggestions to store all the strings of environ in an array? – Blackjaguar Oct 12 '16 at 19:17
  • First of all, I appreciate the effort! However, my course clearly states I am no supposed to use any tools not covered yet by the lectures. Sadly, I cannot use vector as of yet. I will however remember this solution for any future programs. Do you happen to know a solution with the class as I provided (i.e. with the d_str array). I am not allowed to add any other data members or modify these. – Blackjaguar Oct 12 '16 at 19:24
  • not a problem, see my edit, just not "real" C++. What pedagogy is it? You cannot use `vector`, so maybe you could be punished for using `string`. Both are part of the C++ library now. Tell your teacher "come on it's 2016 now". – Jean-François Fabre Oct 12 '16 at 19:31
  • Perfect, thanks a lot! Why do we need to copy to count the amount of elements? Every teacher has his or her own style I guess ;) – Blackjaguar Oct 12 '16 at 19:35
  • If you don't make a copy of `envp` you reach `nullptr` and you cannot copy the elements because you've lost the original pointer. – Jean-François Fabre Oct 12 '16 at 19:45