2

we have a data structure

struct MyData
{
       int length ;
       char package[MAX_SIZE];  
};

where MAX_SIZE is a fixed value . Now we want to change it so as to support "unlimited" package length greater than MAX_SIZE . one of the proposed solution is to replace the static array with a pointer and then dynamically allocating the size as we require For EX

struct MyData
{
       int length ;
       char* package;  
};

and then

package = (char*)malloc(SOME_RUNTIME_SIZE) ;

Now my question is that is this the most efficient way to cater to the requirement OR is there any other method .. maybe using STL data structures like growable arrays etc etc . we want a solution where most of the code that works for the static char array should work for the new structure too ..

Martin York
  • 257,169
  • 86
  • 333
  • 562
user66854
  • 865
  • 3
  • 11
  • 15

9 Answers9

7

Much, much better/safer:

struct my_struct
{
    std::vector<char>package;  
};

To resize it:

my_struct s;
s.package.resize(100);

To look at how big it is:

my_struct s;
int size = s.package.size();

You can even put the functions in the struct to make it nicer:

struct my_struct
{
  std::vector<char>package;  

  void resize(int n) {
    package.resize(n);
  }
  int size() const {
    return package.size();
  }
};

my_struct s;
s.resize(100);
int z = s.size();

And before you know it, you're writing good code...

Jimmy J
  • 1,953
  • 1
  • 14
  • 20
  • Why encapsulate a single field into a struct? A typedef would be enough. – sharptooth Mar 06 '09 at 07:36
  • I think Jimmmy was assuming there is other stuff in there (I know I did). – RedBlueThing Mar 06 '09 at 07:41
  • Yes, I assume there's more to it. Also, struct is a stepping stone to proper encapsulation. – Jimmy J Mar 06 '09 at 08:13
  • Pardon the ignorance, but why would one want to make a structure with functions in it? It seems to me that that's what a class basically is. What am I missing? – Will Mc Mar 06 '09 at 08:18
  • you are missing that a struct and a class is the same - just with different default protection (private vs public). the choice is arbitrary. if more functions are public than private, struct is a good choice imho. but some crappy compilers moan (none that i know though) – Johannes Schaub - litb Mar 06 '09 at 08:21
  • As noted, struct and class are basically the same. I used "struct" because that's what he used and I was being as gentle as possible. – Jimmy J Mar 06 '09 at 08:37
  • Ok, thanks you guys. Oddly, a friend of mine asked a week ago if structs could have functions. I replied "That would be a class." Then I saw this example, and I doubted my conviction. Thanks again :) – Will Mc Mar 06 '09 at 08:59
  • It's probably good to think of struct/class as different and use them to express your "intent" in the source code, but the compiler sees them identically (apart from class having 'private' access by default) – Jimmy J Mar 06 '09 at 10:24
4

using STL data structures like growable arrays

The STL provides you with a host of containers. Unfortunately, the choice depends on your requirements. How often do you add to the container? How many times do you delete? Where do you delete from/add to? Do you need random access? What performance gurantees do you need? Once you have a sufficiently clear idea about such things look up vector, deque, list, set etc.

If you can provide some more detail, we can surely help pick a proper one.

dirkgently
  • 108,024
  • 16
  • 131
  • 187
2

I would also wrap a vector:

// wraps a vector. provides convenience conversion constructors
// and assign functions. 
struct bytebuf {
    explicit bytebuf(size_t size):c(size) { }

    template<size_t size>
    bytebuf(char const(&v)[size]) { assign(v); }

    template<size_t size>
    void assign(char const(&v)[size]) {
        c.assign(v, v+size);
    }

    // provide access to wrapped vector
    std::vector<char> & buf() {
        return c;
    }

private:
    std::vector<char> c;
};

int main() {
    bytebuf b("data");
    process(&b.buf()[0], b.buf().size()); // process 5 byte

    std::string str(&b.buf()[0]);
    std::cout << str; // outputs "data"

    bytebuf c(100);
    read(&c.buf()[0], c.buf().size()); // read 100 byte
    // ...
}

There is no need to add many more functions to it, i think. You can always get the vector using buf() and operate on it directly. Since a vectors' storage is contiguous, you can use it like a C array, but it is still resizable:

c.buf().resize(42)

The template conversion constructor and assign function allows you to initialize or assign from a C array directly. If you like, you can add more constructors that can initialize from a set of two iterators or a pointer and a length. But i would try keeping the amount of added functionality low, so it keeps being a tight, transparent vector wrapping struct.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • That's just silly! No need to do all that extra work, stop showing off we know you are good ;-) – Martin York Mar 06 '09 at 08:53
  • All that "explicit" and "template" and "char const(&v)[]" stuff. Go easy on the guy, he's obviously a newbie... – Jimmy J Mar 06 '09 at 10:28
  • explicit is not a big word. it's good style to use it. i've used the template to be able to directly pass a C array. i've tried to keep this low. it's not implementing a container requirement even. if he has questions on the template, he is welcome to ask. it's not like i tell him "rtfm" – Johannes Schaub - litb Mar 06 '09 at 10:54
  • he's chosen C++. that means he wants to take a hard trip. making c++ look easy when in fact it has myriads of pitfalls (like the unwanted implicit conversions if explicit is not used) won't help him in the long run. – Johannes Schaub - litb Mar 06 '09 at 10:58
  • litb - I'm with you on this! :-) – Johann Gerell Dec 22 '09 at 23:52
  • You have a compiler in your head. – toto Dec 23 '09 at 00:20
  • overkill .. i am a firm believer of KISS principle .. i am a newbie in c++ but not so in C .. i am just not that well versed in c++ STL .. thanks for your answers .. i have decided to go for a vector implementation ... – user66854 Jan 19 '11 at 05:10
  • These comments are just silly. There are no "big words" in my answer, and a newbie saying my solution is "overkill". Great! – Johannes Schaub - litb Jan 19 '11 at 11:23
  • happens .. dont get your knickers in a knot over this :-) ... the simpler your code the better it is to maintain ... you dont use a magnum when all you have to do is kill a mosquito .. anyway my problem was solved with a very widely used C trick .. i added struct MyData { int length ; char package[1]; }; Mydata* ptr = (Mydata*)malloc(4 + RUNTIME_SIZE) ... ... this works beautifully ..ugly but totally workable ... – user66854 Mar 16 '11 at 09:01
2

If this is C:

Community
  • 1
  • 1
unwind
  • 391,730
  • 64
  • 469
  • 606
2

If you're using the character array as an array of characters, use a std::vector<char> as that's what vectors are for. If you're using the character array as a string, use a std::string which will store its data in pretty much the same way as a std::vector<char>, but will communicate its purpose more clearly.

Max Lybbert
  • 19,717
  • 4
  • 46
  • 69
1

Yep, I would use an STL vector for this:

struct
{
    std::vector<char> package;
    // not sure if you have anything else in here ?
};

but your struct length member just becomes package.size ().

You can index characters in the vector as you would in your original char array (package[index]).

RedBlueThing
  • 42,006
  • 17
  • 96
  • 122
1

use a deque. sure a vector will work and be fine, but a deque will use fragmented memory and be almost as fast.

Gregor Brandt
  • 7,659
  • 38
  • 59
0

How are you using your structure?
Is it like an array or like a string?

I would just typedef one of the C++ containers:

typedef  std::string  MyData; // or std::vector<char> if that is more appropriate
Martin York
  • 257,169
  • 86
  • 333
  • 562
-1

What you have written can work and is probably the best thing to do if you do not need to resize on the fly. If you find that you need to expand your array, you can run

package = (char*)realloc((void*)package, SOME_RUNTIME_SIZE) ;

You can use an STL vector

include <vector>

std::vector<char> myVec();  //optionally myVec(SOME_RUNTIME_SIZE)

that you can then resize using myVec.resize(newSize) or by using functions such as push_back that add to the vector and automatically resize. The good thing about the vector solution is that it takes away many memory management issues -- if the vector is stack-allocated, its destructor will be called when it goes out of scope and the dynamically-allocated array underlying it will be deleted. However, if you pass the vector around, the data will get copied that can be slow, so you may need to pass pointers to vectors instead.

bsdfish
  • 2,434
  • 1
  • 21
  • 20
  • "package = (char*)realloc((void*)package, SOME_RUNTIME_SIZE) ;" -- Read the definition of realloc and figure out why you're not using it properly. Anyway the other person's answer was correct, std::string. – Windows programmer Mar 06 '09 at 07:37
  • I guess it depends how you are using this thing (I actually mean vector and have since edited my answer). Do you wan't a null terminated string or an array of characters? – RedBlueThing Mar 06 '09 at 07:43