How to initialize an array whose size is initially unknown? - c++

Say I have this:
int x;
int x = (State Determined By Program);
const char * pArray[(const int)x]; // ??
How would I initialize pArray before using it?
Because the initial size of the Array is determined by user input
Thanks!

Size of dynamically created array on the stack must be known at compile time.
You can either use new:
const char* pArray = new char[x];
...
delete[] pArray;
or better to use std::vector instead (no need to do memory management manually):
vector<char> pArray;
...
pArray.resize(x);

You cannot initialize an array at compile-time if you are determining the size at run-time.
But depending on what you are trying to do, a non-const pointer to const data may provide you with what you're going for.
const char * pArray = new const char[determine_size()];
A more complete example:
int determine_size()
{
return 5;
}
const char * const allocate_a( int size )
{
char * data = new char[size];
for( int i=0; i<size; ++i )
data[i] = 'a';
return data;
}
int main()
{
const char * const pArray = allocate_a(determine_size());
//const char * const pArray = new char[determine_size()];
pArray[0] = 'b'; // compile error: read-only variable is not assignable
pArray = 0 ; // compile error: read-only variable is not assignable
delete[] pArray;
return 0;
}
I do agree with others that a std::vector is probably more what you're looking for. If you want it to behave more like your const array, you can assign it to a const reference.
#include <vector>
int main()
{
std::vector<char> data;
data.resize(5);
const std::vector<char> & pArray = data;
pArray[0] = 'b'; // compile error: read-only variable is not assignable
}

The example you provided attempts to build the array on the stack.
const char pArray[x];
However, you cannot dynamically create objects on the stack. These types of items must be known at compile time. If this is a variable based on user input then you must create the array in heap memory with the new keyword.
const char* pArray = new char[x];
However, not all items need to be created on the heap. Heap allocation is normally a lot slower then stack allocation. If you want to keep your array on the stack you could always use block based initialization.
#define MAX_ITEMS 100
const char pArray[MAX_ITEMS]
It should be noted that the second option is wasteful. Because you can not dynamically resize this array you must allocate a large enough chunk to hold the maximum number of items your program could create.
Finally, you can always use data structures provide by C++. std::vector is such a class. It provides you a good level of abstraction and item are stored in contingent memory like an array. As noted by one of the other answers you should use the resize option once you know the final size of your vector.
std::vector<char> pArray;
pArray.resize(X);
The reason for this is every time you add an element to a vector, if it no longer has enough room to grow, it has to relocate all items so they can exist next to one another. Using the resize method helps prevent vector from having to grow as you add items.

Related

How to initialize a constant array in heap memory using C++?

In C++, we can allocate heap memory for a dynamic array, but how can we initialize it if it's a read only array? Here is an example:
const char* str = new char[3];
After operating this statement, the system seems to initialize variable str with garbage value implicitly which means i cannot change its value since it has a constant qualifier. So how can i creat a constant string in heap memory and intialize it explicitly?
If i want to creat a object in heap memory, i need a pointer to the object. But if it's constant, i cannot even change it with the pointer after its creation in heap memory. So it became a vicious circle for me.
You can start with char * modify the array, then convert it to const char *:
char *str = new char[3];
// str[i] = ...
const char *cstr = str;
But unless you're trying to practice dynamic memory management, none of this should be necessary. Just use std::string or std::vector<char>.
Your operator new call doesn't allocate const memory. It gets converted to const when you assign it to the variable. The solution is to make a temporary variable that's not const, write the data to it and then finally convert it to a const pointer:
#include <cstring>
#include <memory>
std::unique_ptr<const char[]> PutBytesOntoHeap(const char* data, size_t size)
{
std::unique_ptr<char[]> result(new char[size]);
memcpy(result.get(), data, size);
return result;
}
In current c++ avoid calling new/delete explicitly, only use it internally in datastructures (and even then std::make_unique is prefered). So use std::vector (or alternatively std::string/std::string_view)
#273K Also note most C++ books (teachers, online material) are out of date.
#include <vector>
int main()
{
std::vector<char> str{ 'a', 'b', 'c' }; // this will do the memory allocation for you
// for local use (when a legacy api needs a pointer, otherwise don't use)
const char* ptr = str.data();
return 0;
// std::vector goes out of scope
// will free the allocated memory (so you can't forget to call delete[])
}
if it's constant, i cannot even change it with the pointer after its creation in heap memory
In
const char* str = new char[3];
you actually create a non-const char array and assign it to a const char*. You could just assign it to a char* instead, make the changes you want and then return a const char*. Example:
auto str = []() -> const char* {
char* rv = new char[3];
rv[0] = '1';
rv[1] = '2';
rv[2] = '\0';
return rv;
}();
how can i creat a constant string in heap memory and intialize it explicitly?
You use new const char[] with an initializer:
auto str = new const char[3]{'1', '2', '\0'};
A helper function could look like this:
#include <cstddef>
#include <iostream>
#include <utility>
template <std::size_t N>
auto make_const_cstring(const char (&s)[N]) {
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
return new const char[N]{s[Is]...};
}(std::make_index_sequence<N>());
}
int main() {
auto str = make_const_cstring("Hello world");
std::cout << str << '\n';
delete[] str;
}
If you want to use an array after the function that created it returns, allocate that array in the heap, not in the run-time stack. Expression new T[size] allocates a new array with size variables in it, each of type T. Remember that an array is treated just like a pointer to the first thing in the array. So expression new int[25] has type int*. Statement
int* A = new int[25];
allocates a new array of 25 ints and stores a pointer to the first one into variable A.
The size can be given by any expression that yields an integer. For example, if you already have an integer variable called n that currently holds 50, then
double* B = new double[n];
allocates an array of 50 doubles.

swizzle/modify array access

I have an array of bytes that I want to change how it's accessed. Here's the array:
char bytes[100];
I want to have another array that changes how the original array is accessed. If we could put references in array, it would look something like this:
char& bytes_ref[50];
for(size_t i = 0; i < 50; i++){
bytes_ref[i] = bytes[i * 2];
}
Though array of references aren't valid. I came up with this that in theory does what I want:
#include <iostream>
struct Byte {
char* ref;
Byte(){}
Byte(char& c){
ref = &c;
}
operator char&() const {
return *ref;
}
};
int main(){
char bytes[100];
Byte bytes_ref[50];
for(size_t i = 0; i < 50; i++){
bytes_ref[i] = bytes[i * 2];
}
}
Though this works like I want it to, it takes up a ton of space.
Is there some way to do this without using up 7 more bytes per entry? My instinct is no, but I'm hopeful there may be some kind of special functionality in C++ that could do this, or maybe do some direct memory manipulation and access.
The reason I want to do this is I have an array of bytes that represent an image in NV21 format. I want to create a separate array that references the bytes in the original buffer but takes half the pixels, effectively resizing the image on the fly.
I have to pass a char** to an uncontrolled library.
Thanks in advance!
I do not think you can use less memory than one pointer per element
If you need to pass an array of char* to an uncontrolled library, I understand that you have to allocate the whole array because that is what the library is expecting. The code would like:
std::array<char*, 50> bytes_ref;
for(size_t i = 0; i < bytes_ref.size(); ++i){
bytes_ref[i] = &bytes[i * 2];
}
Then, you can pass the array as:
f(bytes_ref.data());
If you would not need to use char**, you would have more options. You may use std::reference_wrapper although its size is similar to a pointer. If you always have to skip 2 elements, you may create an object for this. For example:
class Wrapper {
public:
Wrapper(char *origin) : m_origin(origin) {}
char* operator[](size_t index) {return m_origin + 2*index;}
private:
char *m_origin;
};
The above will return a pointer to every 2 elements using the [] operator.

How to initialize an array that is part of a struct typedef?

If I have a typedef of a struct
typedef struct
{
char SmType;
char SRes;
float SParm;
float EParm;
WORD Count;
char Flags;
char unused;
GPOINT2 Nodes[];
} GPATH2;
and it contains an uninitialized array, how can I create an instance of this type so that is will hold, say, 4 values in Nodes[]?
Edit: This belongs to an API for a program written in Assembler. I guess as long as the underlying data in memory is the same, an answer changing the struct definition would work, but not if the underlying memory is different. The Assembly Language application is not using this definition .... but .... a C program using it can create GPATH2 elements that the Assembly Language application can "read".
Can I ever resize Nodes[] once I have created an instance of GPATH2?
Note: I would have placed this with a straight C tag, but there is only a C++ tag.
You could use a bastard mix of C and C++ if you really want to:
#include <new>
#include <cstdlib>
#include "definition_of_GPATH2.h"
using namespace std;
int main(void)
{
int i;
/* Allocate raw memory buffer */
void * raw_buffer = calloc(1, sizeof(GPATH2) + 4 * sizeof(GPOINT2));
/* Initialize struct with placement-new */
GPATH2 * path = new (raw_buffer) GPATH2;
path->Count = 4;
for ( i = 0 ; i < 4 ; i++ )
{
path->Nodes[i].x = rand();
path->Nodes[i].y = rand();
}
/* Resize raw buffer */
raw_buffer = realloc(raw_buffer, sizeof(GPATH2) + 8 * sizeof(GPOINT2));
/* 'path' still points to the old buffer that might have been free'd
* by realloc, so it has to be re-initialized
* realloc copies old memory contents, so I am not certain this would
* work with a proper object that actaully does something in the
* constructor
*/
path = new (raw_buffer) GPATH2;
/* now we can write more elements of array */
path->Count = 5;
path->Nodes[4].x = rand();
path->Nodes[4].y = rand();
/* Because this is allocated with malloc/realloc, free it with free
* rather than delete.
* If 'path' was a proper object rather than a struct, you should
* call the destructor manually first.
*/
free(raw_buffer);
return 0;
}
Granted, it's not idiomatic C++ as others have observed, but if the struct is part of legacy code it might be the most straightforward option.
Correctness of the above sample program has only been checked with valgrind using dummy definitions of the structs, your mileage may vary.
If it is fixed size write:
typedef struct
{
char SmType;
char SRes;
float SParm;
float EParm;
WORD Count;
char Flags;
char unused;
GPOINT2 Nodes[4];
} GPATH2;
if not fixed then change declaration to
GPOINT2* Nodes;
after creation or in constructor do
Nodes = new GPOINT2[size];
if you want to resize it you should use vector<GPOINT2>, because you can't resize array, only create new one. If you decide to do it, don't forget to delete previous one.
also typedef is not needed in c++, you can write
struct GPATH2
{
char SmType;
char SRes;
float SParm;
float EParm;
WORD Count;
char Flags;
char unused;
GPOINT2 Nodes[4];
};
This appears to be a C99 idiom known as the "struct hack". You cannot (in standard C99; some compilers have an extension that allows it) declare a variable with this type, but you can declare pointers to it. You have to allocate objects of this type with malloc, providing extra space for the appropriate number of array elements. If nothing holds a pointer to an array element, you can resize the array with realloc.
Code that needs to be backward compatible with C89 needs to use
GPOINT2 Nodes[1];
as the last member, and take note of this when allocating.
This is very much not idiomatic C++ -- note for instance that you would have to jump through several extra hoops to make new and delete usable -- although I have seen it done. Idiomatic C++ would use vector<GPOINT2> as the last member of the struct.
Arrays of unknown size are not valid as C++ data members. They are valid in C99, and your compiler may be mixing C99 support with C++.
What you can do in C++ is 1) give it a size, 2) use a vector or another container, or 3) ditch both automatic (local variable) and normal dynamic storage in order to control allocation explicitly. The third is particularly cumbersome in C++, especially with non-POD, but possible; example:
struct A {
int const size;
char data[1];
~A() {
// if data was of non-POD type, we'd destruct data[1] to data[size-1] here
}
static auto_ptr<A> create(int size) {
// because new is used, auto_ptr's use of delete is fine
// consider another smart pointer type that allows specifying a deleter
A *p = ::operator new(sizeof(A) + (size - 1) * sizeof(char));
try { // not necessary in our case, but is if A's ctor can throw
new(p) A(size);
}
catch (...) {
::operator delete(p);
throw;
}
return auto_ptr<A>(p);
}
private:
A(int size) : size (size) {
// if data was of non-POD type, we'd construct here, being very careful
// of exception safety
}
A(A const &other); // be careful if you define these,
A& operator=(A const &other); // but it likely makes sense to forbid them
void* operator new(size_t size); // doesn't prevent all erroneous uses,
void* operator new[](size_t size); // but this is a start
};
Note you cannot trust sizeof(A) any where else in the code, and using an array of size 1 guarantees alignment (matters when the type isn't char).
This type of structure is not trivially useable on the stack, you'll have to malloc it. the significant thing to know is that sizeof(GPATH2) doesn't include the trailing array. so to create one, you'd do something like this:
GPATH2 *somePath;
size_t numPoints;
numPoints = 4;
somePath = malloc(sizeof(GPATH2) + numPoints*sizeof(GPOINT2));
I'm guessing GPATH2.Count is the number of elements in the Nodes array, so if it's up to you to initialize that, be sure and set somePath->Count = numPoints; at some point. If I'm mistaken, and the convention used is to null terminate the array, then you would do things just a little different:
somePath = malloc(sizeof(GPATH2) + (numPoints+1)*sizeof(GPOINT2));
somePath->Nodes[numPoints] = Some_Sentinel_Value;
make darn sure you know which convention the library uses.
As other folks have mentioned, realloc() can be used to resize the struct, but it will invalidate old pointers to the struct, so make sure you aren't keeping extra copies of it (like passing it to the library).

What is the difference between an array and a dynamic array?

What is the difference between the following two types of array?
int array1[10];
int* array2 = new int[10];
The main difference is that a dynamic array is created on the heap. A dynamic array's size can be determined at runtime.
The difference in the below:
int x = 10;
int array1[10];
int *array2 = new char[x];
Is that array2 is pointing to the first element of an array and not the actual full array.
Note:
assert(sizeof(array1) == 40);
assert(sizeof(array2) == 4);
Memory on the heap that is created with new should eventually be destroyed using delete.
Since array2 is created on the heap, and is an array you will need to delete it with delete[] though.
Note: You can actually create a pointer to a full array and not just the first element:
int array1[10];
int *pointerToFirstElement = array1;
int (*pointerToFullArray)[10] = &array1;
int sizeOfFirstPointer = sizeof(pointerToFirstElement);
int sizeOfSecondPointer = sizeof(pointerToFullArray);
assert(sizeOfFirstPointer == sizeOfSecondPointer);//==4 since both are pointers
However what they point to have different sizes:
int sizeOfFirst = sizeof(*pointerToFirstElement);
int sizeOfSecond = sizeof(*pointerToFullArray);
assert(*sizeOfFirst == 4);
assert(*sizeOfSecond == 40);
A dynamic array is created from heap memory at run time and can be dynamically resized/freed as necessary with the new/delete keywords. An array is statically defined at compile time and will -always- take that amount of memory at all times.

Dynamically allocate C struct?

I want to dynamically allocate a C struct:
typedef struct {
short *offset;
char *values;
} swc;
Both 'offset' and 'values' are supposed to be arrays, but their size is unknown until runtime.
How can I dynamically allocate memory for my struct and the struct's arrays?
swc *a = (swc*)malloc(sizeof(swc));
a->offset = (short*)malloc(sizeof(short)*n);
a->values = (char*)malloc(sizeof(char)*n);
Where n = the number of items in each array and a is the address of the newly allocated data structure. Don't forget to free() offsets and values before free()'ing a.
In C:
swc *s = malloc(sizeof *s); // assuming you're creating a single instance of swc
if (s)
{
s->offset = malloc(sizeof *(s->offset) * number_of_offset_elements);
s->values = malloc(sizeof *(s->values) * number_of_value_elements);
}
In C++:
try
{
swc *s = new swc;
s->offset = new short[number_of_offset_elements];
s->values = new char[number_of_value_elements];
}
catch(...)
{
...
}
Note that in C++, you might be better off using vectors as opposed to dynamically allocated buffers:
struct swc
{
std::vector<short> offset;
std::vector<char> values;
};
swc *a = new swc;
Question: is values supposed to be an array of individual characters or an array of strings? That would change things a bit.
EDIT
The more I think about it, the less satisfied I am with the C++ answer; the right way to do this sort of thing in C++ (assuming you need dynamically allocated buffers as opposed to vectors, which you probably don't) is to perform the memory allocation for offset and values as part of a constructor within the struct type, and have a destructor deallocate those elements when the struct instance is destroyed (either by a delete or by going out of scope).
struct swc
{
swc(size_t numOffset = SOME_DEFAULT_VALUE,
size_t numValues = SOME_OTHER_DEFAULT_VALUE)
{
m_offset = new short[numOffset];
m_values = new char[numValues];
}
~swc()
{
delete[] m_offset;
delete[] m_values;
}
short *m_offset;
char *m_values;
};
void foo(void)
{
swc *a = new swc(10,20); // m_offset and m_values allocated as
// part of the constructor
swc b; // uses default sizes for m_offset and m_values
...
a->m_offset[0] = 1;
a->m_values[0] = 'a';
b.m_offset[0] = 2;
b.m_values[0] = 'b';
...
delete a; // handles freeing m_offset and m_values
// b's members are deallocated when it goes out of scope
}
You have to do it seperately. First allocate the struct, then the memory for the arrays.
In C:
swc *pSwc = malloc(sizeof(swc));
pSwc->offset = malloc(sizeof(short)*offsetArrayLength);
pSwc->values = malloc(valuesArrayLength);
In C++, you shouldn't be doing anything like that.
In C:
typedef struct
{
short *offset;
char *values;
} swc;
/// Pre-Condition: None
/// Post-Condition: On failure will return NULL.
/// On Success a valid pointer is returned where
/// offset[0-n) and values[0-n) are legally de-refrancable.
/// Ownership of this memory is returned to the caller who
/// is responsible for destroying it via destroy_swc()
swc *create_swc(unsigned int size)
{
swc *data = (swc*) malloc(sizeof(swc));
if (data)
{
data->offset = (short*)malloc(sizeof(short)*n);
data->values = (char*) malloc(sizeof(char) *n);
}
if ((data != NULL) && (size != 0) && ((data->offset == NULL) || (data->values == NULL)))
{
// Partially created object is dangerous and of no use.
destroy_swc(data);
data = NULL;
}
return data;
}
void destroy_swc(swc* data)
{
free(data->offset);
free(data->values);
free(data);
}
In C++
struct swc
{
std::vector<short> offset;
std::vector<char> values;
swc(unsigned int size)
:offset(size)
,values(size)
{}
};
You will need a function to do this.
Something like (my C/C++ is rusty)
swc* makeStruct(int offsetCount, int valuesCount) {
swc *ans = new swc();
ans->offset = new short[offsetCount];
ans->values = new char[valuesCount];
return ans;
}
myNewStruct = makeStruct(4, 20);
Syntax may be a bit off but that is generally what you are going to need. If you're using C++ then you probably want a class with a constructor taking the 2 args instead of the makeStruct but doing something very similar.
One thing to add to the many correct answers here: you can malloc an over-sized structure to accommodate a variable sized array in the last member.
struct foo {
short* offset;
char values[0]
};
and later
struct *foo foo1 = malloc(sizeof(struct foo)+30); // takes advantage of sizeof(char)==1
to get room for 30 objects in the values array. You would still need to do
foo1->offsets = malloc(30*sizeof(short));
if you want them to use the same size arrays.
I generally wouldn't actually do this (maintenance nightmare if the structure ever needs to expand), but it is a tool in the kit.
[code here in c. You'll need to cast the malloc's (or better use new and RAII idioms) in c++]
swc* a = malloc(sizeof(*a));
a->offset = calloc(n, sizeof(*(a->offset)));
a->values = calloc(n, sizeof(*(a->values)));
You should not cast void* in c... in c++ you must!
Use malloc function or calloc to allocate memory dynamically .
and search it on google to get examples.
The calloc function initializes allocated memory to zero.
Since nobody has mentioned it yet, sometimes it is nice to grab this chunk of memory in one allocation so you only have to call free() on one thing:
swc* AllocSWC(int items)
{
int size = sizeof(swc); // for the struct itself
size += (items * sizeof(short)); // for the array of shorts
size += (items * sizeof(char)); // for the array of chars
swc* p = (swc*)malloc(size);
memset(p, 0, size);
p->offset = (short*)((char*)swc + sizeof(swc)); // array of shorts begins immediately after the struct
p->values = (char*)((char*)swc + sizeof(swc) + items * sizeof(short)); // array of chars begins immediately after the array of shorts
return p;
}
Of course this is a bit more difficult to read and maintain (especially if you dynamically resize the arrays after it is first allocated). Just an alternative method I've seen used in a number of places.
Most of the answers are correct. I would like to add something that you haven't explicitly asked but might also be important.
C / C++ arrays don't store their own size in memory. Thus, unless you want offset and values to have compile-time defined values (and, in that case, it's better to use fixed-size arrays), you might want to store the sizes of both arrays in the struct.
typedef struct tagswc {
short *offset;
char *values;
// EDIT: Changed int to size_t, thanks Chris Lutz!
size_t offset_count;
size_t values_count; // You don't need this one if values is a C string.
} swc;
DISCLAIMER: I might be wrong. For example, if all offsets of all swc instances have the same size, it would be better to store offset_count as a global member, not as a member of the struct. The same can be said about values and values_count. Also, if values is a C string, you don't need to store its size, but beware of Schlemiel the painter-like problems.
You want to use malloc to allocate the memory, and probably also sizeof() to allocate the correct amount of space.
Something like:
structVariable = (*swc) malloc(sizeof(swc));
Should do the trick.
In addition to the above, I would like to add freeing up the allocated memory as below.,
typedef struct {
short *offset;
char *values;
} swc;
swc* createStructure(int Count1, int Count2) {
swc *s1 = new swc();
s1->offset = new short[Count1];
s1->values = new char[Count2];
return s1;
}
int _tmain(int argc, _TCHAR* argv[])
{
swc *mystruct;
mystruct = createStructure(11, 11);
delete[] mystruct->offset;
delete[] mystruct->values;
delete mystruct;
return 0;
}
**If** you will not be resizing the arrays, then you can get away with a single call to malloc().
swc *new_swc (int m, int n) {
swc *p;
p = malloc (sizeof (*p) + m * sizeof (p->offset[0]) + n * sizeof (p->values[0]);
p->offset = (short *) &p[1];
p->values = (char *) &p->offset[m];
return p;
}
You can then free it with a single call to free().
(In general, there are alignment considerations to take into account, but for an array of shorts followed by an array of chars, you will be fine.)