I want to initialize array of c-strings with zero pointers in MSVC2010
// Foo.h
#pragma once
class Foo {
int sz_;
char **arr_;
public:
Foo();
~Foo();
// ... some other functions
};
// Foo.cpp
#include "Foo.h"
#define INITIAL_SZ 20
Foo::Foo() : sz_(INITIAL_SZ) {
// there I have to initialize arr_ (dynamic array and can be enlarged later)
arr_ = (char **)calloc(INITIAL_SZ * sizeof (char *)); // ???
// or maybe arr_ = new ...
}
How to correct initialize arr_? I was not allowed to use of STL, MFC, etc.
arr = new char*[INITIAL_SZ](); will do - you can even put it in an initialization list.
If you really want to avoid STL, etc., then why not:
arr_ = new char*[INITIAL_SZ]();
You could even put this in the initializer list.
Remember to invoke delete [] arr_ in your destructor. (As #Nawaz points out below, you should probably also follow the Rule of Three, and define a suitable copy-constructor and assignment operator as well.)
1. Build a proper string class
2. Build a proper array class
3. Use the array on strings
Happy chasing memory leaks, double frees and memory corruption.
arr_ = (char **)calloc(INITIAL_SZ * sizeof (char *));
should be
arr_ = (char **)calloc(INITIAL_SZ, sizeof (char *));
The correct way is to redefine arr_ as std::vector<std::string> and to use vector::reserve() to hint at the number of strings you expect to have. Let C++ take care of the memory for you.
But if you must use raw C strings, you probably want:
arr_ = new char *[sz_];
Related
Context:
I try to avoid vectors and replace it with smart pointers as an exercise.
The goal is to benefit from smart pointers to avoid memory leaks without relying on vectors, because that is what I want to try now.
The codes below is just a mean to be easily understood.
I want my c++ code to work.
Update : I would like to stick as much as possible with raw c'ish style for IO: please no std::string or c++ streams in general.
The codes:
C version (working):
typedef struct{
char ** my_arr;
} MyInputs;
...
MyInputs *Doc = malloc(sizeof *Doc);
*Doc->my_arr = malloc(sizeof (*Doc->my_arr) * 2);
Doc->my_arr[0] = malloc(10);
Doc->my_arr[1] = malloc(10);
// Yes, that is stupid to alloc 10 bytes and use only 6 or 5. That is for the example.
memcpy(Doc->my_arr[0],(char*)"Hello\0",6);
memcpy(Doc->my_arr[1],(char*)"Cool\0",5);
printf("%s %s \n",Doc->my_arr[0],Doc->my_arr[1] );
...
C++ version (attempt):
typedef struct {
std::shared_ptr<char*>my_arr;
}MyInputs;
...
std::shared_ptr<MyInputs> MainDoc (static_cast<MyInputs*>(malloc(sizeof (*MainDoc))),free);
std::shared_ptr<char*> Z (static_cast<char**>(malloc(sizeof (**MainDoc->my_arr) * 10)),free);
std::shared_ptr<char> Z[0](static_cast<char*>(malloc(sizeof (char *) * 10)),free);
memcpy(Z[0].get(), (char*)"salut\0", 6);
cout << Z[0] << endl;
...
The obvious:
In the c++ version, the compiler complains about Z and Z[0] being the same and that there is not match for operator [] in the cout.
Well, well, well...
Any ideas that could make the c++ code work that way ? (and again, I know about vectors).
If you insist on using the wrong tool for the job, then you'll want each inner pointer to also be a smart pointer:
shared_ptr<shared_ptr<char>> my_arr;
You can't simply use malloc to create an array of non-trivial types like shared_ptr; use new:
my_arr.reset(new shared_ptr<char>[10], [](shared_ptr<char> * p) {delete [] p;});
Then you can assign or reset the elements. shared_ptr doesn't support [], since it's generally not used for arrays, so use get() to get a pointer to the first element:
my_arr.get()[0].reset(new char[10], [](char * p) {delete [] p;});
Or just replace this gibberish with something sensible
std::vector<std::string> my_arr {"Hello", "Cool"};
struct Rational
{
int a;
int b;
};
struct NextOnFreeList
{
NextOnFreeList *next;
};
// Build the linked-list
NextOnFreeList* freeList = NULL; // head of the linked-list
size_t size = (sizeof(Rational) > sizeof(NextOnFreeList *)) ? sizeof(Rational) : sizeof(NextOnFreeList *);
NextOnFreeList *runner = static_cast <NextOnFreeList *> new char [size]; // LineA
freeList = runner;
for (int i = 0; i < EXPANSION_SIZE; i++) {
runner->next = static_cast <NextOnFreeList *> new char [size];
runner = runner->next;
}
runner->next = 0;
Question 1> LineA
Since the size of Rational(i.e. 8 bytes) is larger than NextOnFreeList(i.e. 4 bytes),
each element in the Linked-list will ONLY use partial of the allocated memory. Is that correct?
// Delete the linked-list
NextOnFreeList *nextPtr = NULL;
for (nextPtr = freeList; nextPtr != NULL; nextPtr = freeList) {
freeList = freeList->next;
delete [] nextPtr; // LineB
}
Question 2> LineB
why should we use 'delete [] nextPtr' instead of 'delete nextPtr'?
Question 3>
Rational* ptr = static_cast<Rational*>( freeList ); // LineC
ptr->a = 10;
ptr->b = 20;
Is it true by LineC, we can bring back all the allocated memory original with size of 'size' and
use the memory to store all elements inside the Rational.
Q1: Yes, but I would rather use std::allocator<Rational>::allocate (or union of both - you will avoid alignment problems this way)
Q2: It is actually bad, because you should cast it to char* first, then use delete[]. Again, using std::allocator would be better. And: It does not matter on default implementation (calls free), but forget I said that ;) ... using malloc/free directly is safer.
Q3:: It is fine, but I am not sure if static_cast will allow that (reinterpret_cast or casting to void* in between may help)
EDIT: I hope your Q3 is not final, because you need to update the free list first (before using the pointer).
2nd EDIT: Links + note: hiding the free-list inside the allocator would be best for C++ (using malloc/free directly in it, or new[] / delete[])
That seems correct. In a 32 bit architecture you most likely overallocated and only a portion of the memory will be used. In a 64 bit architecture most likely the two sizes are the same.
Neither one is appropriate. You allocated that memory as char* so you must delete it as such (by casting back to char* and then delete[]) or you have undefined behavior.
Line C won't compile because the two pointee types are unrelated. If you did use reinterpret_cast you would be violating the strict aliasing rules, again causing undefined behavior.
Q.1:
Yes but that is not the best idea to use static_cast. reinterpret_cast would be more preferable.
Q.2:
I dont there is a defined behavior to recognize your static_cast to accept a simple delete. safest way would be to look at this as the original allocation of array. So cast back to char* and use []delete
Q.3 yep, yes you can.
How do I do a memset for a pointer to an array?
int (*p)[2];
p=(int(*))malloc(sizeof(*p)*100);
memset(p,0,sizeof(*p)*100);
Is this allocation an correct?
you can use calloc.
calloc will replace both malloc and memset.
p = calloc(100, sizeof (*p));
I'll summarize a lot of answers (although I've ignored some of the stylistic variants in favor of my own preferences).
In C:
How to use malloc:
int (*p)[2] = malloc(100 * sizeof(*p));
How to use memset:
memset(p, 0, 100 * sizeof(*p));
How to do both in one statement:
int (*p)[2] = calloc(100, sizeof(*p));
In C++, the same is possible except that you need to cast the results of malloc and calloc: static_cast<int(*)[2]>(std::malloc(100 * sizeof(*p)).
However, C++ provides alternative ways to allocate this:
int (*p)[2] = new int[100][2](); // like calloc.
delete[] p; // *not* delete p
C++ also provides vector, which is usually nice, but unfortunately you cannot create a vector of C-style arrays. In C++03 you can workaround like this:
struct my_array {
int data[2];
};
std::vector<my_array> p(100);
// no need to free/delete anything
I don't think that zeros the elements, although I might be wrong. If I'm right, then to zero you need:
my_array initvalue = {0};
std::vector<my_array> p(100, initvalue);
another way to represent 2 ints:
std::vector<std::pair<int,int> > p(100);
If you can use Boost:
std::vector<boost::array<int, 2> > p(100);
In C++11:
std::vector<std::array<int, 2>> p(100);
I've listed these in increasing order of how good they usually are, so use the last one that isn't blocked by whatever constraints you're working under. For example, if you expect to take a pointer to the first element of one of the inner arrays-of-2-int, and increment it to get a pointer to the second, then std::pair is out because it doesn't guarantee that works.
The elegant way:
typedef int int_arr_2[2];
int_arr_2* p;
p = malloc(sizeof(int_arr_2)*100);
memset(p,0,sizeof(int_arr_2)*100);
The best way:
typedef int int_arr_2[2];
int_arr_2* p;
p = calloc(100, sizeof(int_arr_2));
calloc, unlike malloc, guarantees that all bytes are set to zero.
The memset() line is proper.
For C you don't need malloc casting.
In C++ if you still want to do this, the type cast should be as:
p = (int(*)[2]) malloc(sizeof(*p)*100); // or `static_cast<...>
// ^^^^^^^^^
But I would suggest to change your approach for using std::vector instead. Cleaner, better and "semi-automatic":
std::vector<int*> vi(100); // or std::vector vi(100, nullptr);
Another way with raw pointers is to use new[]:
int **p = new[100](); // allocates and sets to 0
But you have to manage this memory later on by deallocating with delete[]
In C (not C++) you would just do
int (*p)[2] = malloc(sizeof(*p)*100);
memset(*p,0,sizeof(*p)*100);
that is, variables can be initialized with expressions and malloc doesn't need (and should not have) a cast. Then *p is an "lvalue" of your array type that decays to a pointer when passed to memset.
What is Trailing Array Idiom ?
P.S : Googling this term gives The vectors are implemented using the trailing array idiom, thus they are not resizeable without changing the address of the vector object itself.
If you mean the trailing array idiom mentioned in the GCC source code (where your quote comes from), it seems to refer to the old C trick to implement a dynamic array:
typedef struct {
/* header */
size_t nelems;
/* actual array */
int a[1];
} IntVector;
where an array would be created with
IntVector *make_intvector(size_t n)
{
IntVector *v = malloc(sizeof(IntVector) + sizeof(int) * (n-1));
if (v != NULL)
v->nelems = n;
return v;
}
It seems to refer to arrays in structs, which may have a variable array-size. See:
http://blogs.msdn.com/b/oldnewthing/archive/2004/08/26/220873.aspx
and
http://sourceware.org/gdb/current/onlinedocs/gdbint/Support-Libraries.html
Another tip, if you google for an expression put the expression in "" like "trailing array" this will give you more specific results. Google knows about trailing arrays.
I think what is meant is:
struct foo {
... some data members, maybe the length of bar ...
char bar[]; /* last member of foo, char is just an example */
};
It is used by allocating with malloc(sizeof(struct foo)+LEN), where LEN is the desired length of bar. This way only one malloc is needed. The [] can only be used with the last struct member.
And, as fas as I understand the GCC doc, struct foo can also only be (reasonably) used as last member of another struct, because the storage size is not fixed -- or as pointer.
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).