I have a function which gets as a parameter a pointer to array,
e.g. int** segs.
I need to allocate (in the function-body) memory for the array, which has size 100 for example.
My attempt was:
*segs=(int*)(malloc(100));
So far so good.
I put a value into *segs[0], and still everything is great.
But... when I try to reach *segs[1], I get an "invalid write of size 4" error from valgrind, which leads to seg-fault.
I have no idea why does that happen.
I tried to reach to *segs[2], but then I get even something weirder-
Error of uninitialised value of size 8.
Due to operator precedence, *segs[N] is treated as *(segs[N]), which is ok when N is equal to 0. However, when you do the same thing using the index 1, things break since nothing has been allocated for segs[1]
For any index other than zero, you need to use (*segs)[N].
It will be easier to use a temporary pointer in the function.
int* ptr = (int*)(malloc(100));
*segs = ptr;
// and then
ptr[0] = ...; // Good
ptr[1] = ...; // Good
...
ptr[99] = ...; // Still good
Upgrading to C++ Way
Pass the pointer by reference.
void foo(int*& segs) { ... }
Use new instead of malloc to allocate memory.
segs = new int[100];
Better yet, use std::vector insteady raw arrays.
void foo(std::vector<int>& segs) { ... }
Related
In this code:
int * p = new int(44);
p is allocated on the heap and the value it points to is 44;
but now I can also do something like this:
p[1] = 33;
without getting an error. I always thought
int * p = new int(44);
was just another way of saying "P is allocated on the heap and points to an address containing 44" but apparently it makes p a pointer to an array of ints? is the size of this new array 44? Or is this result unusual.
You were right: P is allocated on the heap and points to an address containing 44. There's no array allocated. p[1] = 33; is what they call "undefined behavior". Your program might crash, but it's not guaranteed to crash every single time you do this.
int *p_scalar = new int(5); //allocates an integer, set to 5.
If you access p_scalar[n] (n <> 0) it may crash
In your example, the C++ language gives you a default implementation for the subscript operator for pointers that looks somehow similar to this:
(*Ptr)& operator[](size_t index)
{
return *(address + index*sizeof(*Ptr));
}
This can always be overloaded and replaced for any type. Integers are not an exception, when you say:
int * pointer = alocate_int_array();
pointer[1] = 1;
You're using the compiler-augmented default implementation of that operator.
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.
int* p_bob = new int;
*p_bob = 78;
The above code makes sense to me. I use the de-reference operation to allocation new memory and assign a value of 78.
int* p_dynint = new int[10];
*p_dynint[2] = 12;
This however doesn't make sense. If I try to use the de-reference operator on p_dynint[] I get an error. Why would an array be any different?
*p_bob = 78; this assigns the value 78 to the memory pointed to by p_bob (which represents an int).
p_dynint[2] = 12; simply accesses the 3rd element.
p_dynint[2] is actually equivalent to *(p_dynint+2).
p_dynint[2] is equivalent to *(p_dynint + 2). The derefencing is implied in the [] operator.
It is no real problem to do this:
int* p_dynint=new int[10];
//write first element
*p_dynint=10;
//write second element
*(p_dynint+1)=20;
//write three elements to std::cout
std::cout<<p_dynint[0]<<p_dynint[1]<<p_dynint[10]<<std::endl;
This example also highlights a problem with arrays. You can read and write anything. The output generated by p_dynint[10] is an int but its value is just the next few bytes converted to an int.
Use containers if possible (for further reasoning read this)
SomeObj<unsigned int>* Buffer;
char* BufferPtr = MemoryManager::giveMeSomeBytes(resX*resY*sizeof(SomeObj<unsigned int>));
Buffer = new(BufferPtr) SomeObj<unsigned int>[resX*resY];
when I step past these lines with the debugger, it shows me the values for the variables Buffer and BufferPtr:
BufferPtr: 0x0d7f004c
Buffer: 0x0d7f0050
I don't really understand why those values differ. The way I understand it, placement new should use the memory starting at address 'BufferPtr' to initialize the array elements using theyr default constructors on the allocated memory and return a pointer to the first byte of the first element in the array, which should be exactly the same byte as passed to the placement new operator.
Did I understand something wrong or can someone tell me why the values differ?
thanks!
//edit: ok - i investigated the issue further and got more confusing results:
int size = sizeof(matth_ptr<int>);
char* testPtr1 = (char*)malloc(a_resX*a_resY*sizeof(int));
int* test1 = new(testPtr1) int[a_resX*a_resY];
char* testPtr2 = mmgr::requestMemory(a_resX*a_resY*sizeof(int));
int* test2 = new(testPtr2) int[a_resX*a_resY];
char* testPtr3 = (char*)malloc(a_resX*a_resY*sizeof(matth_ptr<int>));
matth_ptr<int>* test3 = new(testPtr3)matth_ptr<int>[a_resX*a_resY];
char* testPtr4 = mmgr::requestMemory(a_resX*a_resY*sizeof(matth_ptr<int>));
matth_ptr<int>* test4 = new(testPtr4)matth_ptr<int>[a_resX*a_resY];
the debugger returns me the following values for my variables:
size: 4
testPtr1:0x05100418
test1: 0x05100418
testPtr2:0x0da80050
test2: 0x0da80050
testPtr3:0x05101458
test3: 0x0510145c
testPtr4:0x0da81050
test4: 0x0da81054
so it clearly must have something to do with my generic smartpointer class matth_ptr so here it is:
template <class X> class matth_ptr
{
public:
typedef X element_type;
matth_ptr(){
memoryOfst = 0xFFFFFFFF;
}
matth_ptr(X* p)
{
unsigned char idx = mmgr::getCurrentChunkIdx();
memoryOfst = (int)p-(int)mmgr::getBaseAddress(idx);
assert(memoryOfst<=0x00FFFFFF || p==0);//NULL pointer is not yet handled
chunkIdx = idx;
}
~matth_ptr() {}
X& operator*() {return *((X*)(mmgr::getBaseAddress(chunkIdx)+(memoryOfst&0x00FFFFFF)));}
X* operator->() {return ((X*)(mmgr::getBaseAddress(chunkIdx)+(memoryOfst&0x00FFFFFF)));}
X* get() {return ((X*)(mmgr::getBaseAddress(chunkIdx)+(memoryOfst&0x00FFFFFF)));}
template<typename T>
matth_ptr(const matth_ptr<T>& other) {memoryOfst=other.memoryOfst;}//put these two operators into the private part in order to prevent copying of the smartpointers
template<typename T>
matth_ptr& operator=(const matth_ptr<T>& other) {memoryOfst = other.memoryOfst; return *this;}
template<typename T>
friend class matth_ptr;
private:
union //4GB adressable in chunks of 16 MB
{
struct{
unsigned char padding[3]; //3 bytes padding
unsigned char chunkIdx; //8 bit chunk index
};
unsigned int memoryOfst; //24bit address ofst
};
};
can anyone explain me what's going on? thanks!
Be careful with placement new on arrays. In the current standard look to section 5.3.4.12, you'll find this:
new(2,f) T[5] results in a call of operator new[](sizeof(T)*5+y,2,f)
It is clear that it will expect the placement new operator to allocate it additional space beyond what the array contents need. "y" is specified only as a non-negative integral value. It will then offset the result of the new function by this amount.
Also look to 18.4.1.3.4 where it says the placement new operator simply returns the provided pointer. This is obviously the expected part.
Based on 5.3.4.12, since that offset may be different for every invocation of the array, the standard basically means there is no way to allocate the exact amount of size needed. In practice that value is probably constant and you could just add it to the allocation, but his amount may change per platform, and again, per invocation as the standard says.
You're using the array version of the new operator which in your implementation is storing information about the array size in the first few bytes of the memory allocation.
#Mat, This is actually a great question. When I've used placement new[], I've had trouble deleting the storage. Even if I call my own symmetrical placement delete[], the pointer address is not the same as was returned by my own placement new[]. This makes placement new[] completely useless, as you've suggested in the comments.
The only solution I've found was suggested by Jonathan#: Instead of placement new[], use placement new (non-array) on each of the elements of the array. This is fine for me as I store the size myself. The problem is that I have to worry about pointer alignments for elements, which new[] is supposed to do for me.
As others have said, this is due to your C++ implementation storing the size of the array at the start of the buffer you pass to array placement new.
An easy fix for this is to simply assign your array pointer to the buffer, then loop over the array and use regular (non-array) placement new to construct each object in the buffer.
I am declaring an array of void pointers. Each of which points to a value of arbitary type.
void **values; // Array of void pointers to each value of arbitary type
Initializing values as follows:
values = (void**)calloc(3,sizeof(void*));
//can initialize values as: values = new void* [3];
int ival = 1;
float fval = 2.0;
char* str = "word";
values[0] = (void*)new int(ival);
values[1] = (void*)new float(fval);
values[2] = (void*)str;
//Trying to Clear the memory allocated
free(*values);
//Error: *** glibc detected *** simpleSQL: free(): invalid pointer: 0x080611b4
//Core dumped
delete[] values*;
//warning: deleting 'void*' is undefined
//Similar Error.
Now how do I free/delete the memory allocated for values ( the array of void pointers)?
I suspect the issue is with the way that you allocated values: values = (void*)calloc(3,sizeof(void)). That should be sizeof(void *) rather than just sizeof(void).
sizeof(void) may be zero or something else that makes no sense, so you're not really allocating any memory to begin with... it's just dumb luck that the assignments work, and then the error pops up when you try to deallocate the memory.
EDIT: You're also asking for trouble by alternating between C++-style new/delete with C-style malloc/free. It is okay to use them both as long as you don't delete something you malloc'ed or free something you new'ed, but you're going to mix them up in your head if you go like this.
You have 3 things that are dynamically allocated that need to be freed in 2 different ways:
delete reinterpret_cast<int*>( values[0]);
delete reinterpret_cast<float*>( values[1]);
free( values); // I'm not sure why this would have failed in your example,
// but it would have leaked the 2 items that you allocated
// with new
Note that since str is not dynamically allocated it should not (actually cannot) be freed.
A couple of notes:
I'm assuming that the sizeof(void)
was meant to be sizeof(void*)
since what you have won't compile
I'm not going to say anything about
your seemingly random casting except
that it looks like code that ready
for disaster in general
This is the perfect situation for the boost::any class
Also you may want to consider using a vector rather than allocating your own memory.
std::vector<boost::any> data;
boost::any i1 = 1; // add integer
data.push_back(i1);
boost::any f1 = 1.0; // add double
data.push_back(f1);
data.push_back("PLOP"); // add a char *
std:: cout << boost::any_cast<int>(data[0]) + boost::any_cast<double>(data[1])
<< std::endl;
Going back to your original code the main problem was:
values = (void*)calloc(3,sizeof(void));
// This should have been
void** values = (void**)calloc(3,sizeof(void*));
// Freeing the members needs care as you need to cast them
// back to the correct type before you release the memory.
// now you can free the array with
free(values);
Also note: Though it is not illegal to use both new/delete and calloc/free in the same piece of code it is frowned upon. Mainly because it is easy to get things mixed up and that could potentially be fatal.
You're mixing new and *alloc(). That's a no-no, and can lead to undefined results.
I'm not sure why you are using new if you're doing things in C (referencing the tag here).
I would malloc the individual pieces of the array I need and then free them when I'm done I suppose. You can't free something you didn't first malloc. You also can't delete a void pointer.
Note that you're also not deleting values[0] and values[1] which is a memory leak, Yet by your design you can't free values[2] since its a pointer into you .data section.
You'd have to keep track of how many void* were originally calloc'd, and iterate over them, free-ing each one, then free the original values variable.
darn formatting... (the preview is working fine).
int ct = 3;
values = (void*)calloc(ct,sizeof(void));
//can initialize values as: values = new void* [3];
int ival = 1;
float fval = 2.0;
char* str = "word";
values[0] = (void*)new int(ival);
values[1] = (void*)new float(fval);
values[2] = (void*)str;
for ( int i = 0; i < ct; i++ ) [
delete( values[i] );
}
free( values );