0

I am trying to find a guide and even found this, but it didn't provide an answer. My question is how to initialize a C array in a constructor? Below I put a hypothetical example of what I think of doing, however I have no clue of whether it is ok but faulty, perfect, or simply there is something wrong and there would be a way to make it better.

class A{
private:
    char* a;
    int b;
public:
    A(char*, int);
}

A::A(char* _a, int _b){
    strcpy(a, _a);
    b = _b
}

int main(){
    A tempA;
    char arr[50];
    int c = 40;

    strcpy(arr,"derp")
    tempA = new A(arr,c)

    return 0;
}

I have no C++ expert close to me at the moment so I would appreciate to receive as much feedback as possible. Also sorry if this is a duplicate question, but I really found nothing on this out there.

Community
  • 1
  • 1
Sofia Alegre
  • 21
  • 1
  • 4

4 Answers4

4

If you want to store a string, you can store a std::string:

class A{
private:
    std::string a;
    int b;
public:
    A(std::string const&, int);
}

A::A(std::string const& _a, int _b) : a(_a), b(_b) {}

If your instructor insists that you treats pointers to characters as strings, then you have a complicated matter on your hand, because you have to deal with managing the memory that character points to by itself, lest you end up leaking memory. In other words, you need to implement something similar to std::string.

So, assuming you really need to do this...

  • Whenever you use new you need a matching delete to release the memory allocated by new;
  • You probably want new to be called by the constructor of a class;
  • You can get delete done for you automatically if use objects of automatic storage duration of a class with a proper destructor that does that clean up;
  • That class can either be made non-copyable (e.g. by making a private copy constructor and copy assignment operator), or made copyable if you write proper copy constructor and copy assignment operator;
  • You can easily make copies using the std::copy algorithm, or, if that is restricted as well for arbitrary reasons, you can probably use the old memcpy or strcpy functions.

This is not very simple, but if you do this you will have a pretty handy class that manages the memory automatically for you, leaving you free to focus on other issues.

Community
  • 1
  • 1
R. Martinho Fernandes
  • 209,766
  • 68
  • 412
  • 492
  • Sorry, I cannot use strings, and I just added the missing part of the code. Sorry about that confusion. – Sofia Alegre Feb 01 '12 at 19:33
  • @SofiaAlegre: Please say what you really need to do, and present a minimal, representative and *complete* example of your needs. This half-baked "oh but I cannot do ABC for no reason I will share" isn't going to get you a good answer. Just because *you think* you're on the right track doesn't make this the best approach. – Kerrek SB Feb 01 '12 at 19:35
  • Basically I need to create several user-account objects, through a user database which is invoked in the main method after collecting all the data from the [actual] user (me). My purpose in this specific "question" is to learn how to pass values from one char array in the main method to another in an specific newly-created class (a.k.a. the user-account object). Does that answer your question? – Sofia Alegre Feb 01 '12 at 19:44
1

If you need to use c-string (array of characters), you can use a while loop. Please also remember that A quoted string in C++ (for example: "test") is c-string but not a string.

class A
{
private:
    char* a;
    int b;
public:
    char * get() {return a;}
    A(char*, int);
    A();
};

A::A(char* _a, int _b)
{
    int i=0, lenth=0;
    while(_a[i++])
        lenth++;
    a= new char[lenth+1];
    i=0;
    while(_a[i])
    {
        a[i]=_a[i];  
        i++;
    }
    a[i]=_a[i]; 

    b = _b;
}

int main()
{
    A *tempA;
    char arr[50];
    int c = 40;

    strcpy(arr,"test string");
    tempA = new A(arr,c);
    cout << tempA->get();

    return 0;
}
haberdar
  • 503
  • 5
  • 6
1

I assume this is an exercise and you are trying to create your own string class. I think this is a good exercise, actually. It is actually very very tough to do.

In any case, once thing you need to know about C++ is "ownership". In this case your class A will own the memory it allocates, and will be responsible for deleting it later.

You need to allocate the memory with new[]. And then you must delete it later with delete[]. The latter will be done in the destructor of A.

class A
{ 
  private:     
      char* a;     
      int b; 

  public:     
      A(const char*, int); 
      ~A();

};

A::A( const char * a_, int b_ )
 : a( new char[b_+1], b( b_ )
{
    strncpy( a, a_, b ); // could also use memcpy which would allow embedded nulls,
         // in which case you must also add the null terminator yourself.
}

A::~A()
{
    delete[] a;
}

I have assumed that the user that creates your class passes in the length of the string as the 2nd parameter therefore your class must be smart to allocate the extra character for the null terminator

Your class is not complete yet. You need to handle: - how users will read the string back. - copying your class - assigning your class.

Note that you will get an automatically generated copy and assign which will copy and assign each member of your class. The issue is that you will have 2 instances now holding the same pointer and both of them will try to delete it. In addition, the class that is being assigned to already has a pointer it needs to delete, and this pointer will end up lost in space (a memory leak).

I am not going to answer that for you because your exercise is to work out how to manage this situation.

CashCow
  • 29,087
  • 4
  • 53
  • 86
0

strcpy(a, _a) won't do what you want: it assumes that a already points to some memory large enough to contain whatever is in _a, and that isn't the case.

This is the smallest change to your current code:

A::A(char *_a, int _b)
{
  a = strdup(_a); // makes a copy
  b = _b;
}

More idiomatic: using the initializer list, and promising we won't modify the array passed in (note the const):

A::A(char const *_a, int _b)
  : a(strdup(_a)), b(_b)
{
  // all the work was done above
}

And in general, it would be better C++ style to use std::string and let it worry about the memory for you:

class A
{
  std::string a;
  int b;
public:
  A(char const *_a, int _b) : a(_a), b(_b) {}

  // we can provide two versions, so you can pass in a std::string as well
  A(std::string const &_a, int _b) : a(_a), b(_b) {}
};

Since you can't use std::string for this assignment, you don't get the memory management for free, so you need to write a destructor:

A::~A()
{
  free(a);
}

otherwise your copied char * array will be leaked when the instance of A dies. The code in your question will leak the whole A object anyway, by the way.

Useless
  • 55,472
  • 5
  • 73
  • 117
  • Thank you, I love strings too, but my professor is restricting us for now to C strings only. – Sofia Alegre Feb 01 '12 at 19:37
  • You shouldn't mention `strdup` without mentioning `free`. – R. Martinho Fernandes Feb 01 '12 at 19:37
  • Well, `strdup` is the C-style way of doing it. Oh, that reminds me - I forgot to add a destructor ... @R.MartinhoFernandes - snap! – Useless Feb 01 '12 at 19:38
  • You shouldn't mention destructors without mentioning the rule of three! And btw, `strdup` is part of POSIX, not C, nor C++. – R. Martinho Fernandes Feb 01 '12 at 19:51
  • sigh, this answer is just going to grow and grow – Useless Feb 01 '12 at 19:56
  • strdup uses malloc so your destructor would have to call free. There is no law against using methods from the C library in C++, in fact the standard string allocator probably uses malloc and char_traits uses things like memset, memmove, memcmp all over the place... – CashCow Feb 02 '12 at 11:23