//char char **p; declared in .h file
size_t bs = 5;
size_t Size = sizeof(obj);
p = (char**)malloc(bs);
for (size_t i = 0; i < bs;i++){p[i] = (char*)malloc(Size);}
for (size_t j = 0; j < bs-1; j ++){p[j] = &(p[j + 1][0]); }
for (size_t i = 0; i < bs; i++){free(p[i]);}
free(p);
my code stalls up when trying to free the last element of p in the for loop. Anyone what i might be doing wrong?
EDIT: I still have the same problem even when changing it to (char*)malloc(bs sizeof(char *));
this still does not work:
size_t bs = 5;
size_t Size = sizeof(obj);
p = (char**)malloc(bs* sizeof(char *));
for (size_t i = 0; i < bs;i++){p[i] = (char*)malloc(Size);}
for (size_t j = 0; j < bs-1; j ++){p[j] = &(p[j + 1][0]); }
for (size_t i = 0; i < bs; i++){free(p[i]);}
free(p);
using new instead of malloc does not solve the issue either
However this code frees up the memory fine.
size_t bs = 5;
size_t Size = sizeof(obj);
p = (char**)malloc(bs* sizeof(char *));
for (size_t i = 0; i < bs;i++){p[i] = (char*)malloc(Size);}
for (size_t i = 0; i < bs; i++){free(p[i]);}
free(p);
so the problem seem to be something with this piece of code
for(size_t j = 0; j < bs-1; j ++){p[j] = &(p[j + 1][0]); }
I want this to be an implicit linked list, anyone know have an idea what i am doing wrong?
You are not allocating enough space for the pointers. Change to
p = malloc(bs * sizeof(char*));
At the first malloc, you donĀ“t need 5 byte, but 5 times a pointer.
p = (char**)malloc(bs * sizeof(char *));
The problem is that you:
allocate an array of 5 pointers
allocate 5 arrays of characters and store them in that first array
move those pointers down in the array, overwriting (and losing) the first pointer and duplicating the last one
attempt to free the 5 pointers in the array.
So on this last step, you free a pointer twice (as the last two entries at p[3] and p[4] are the same), causing undefined behavior.
You say you want "an implicit linked list", implying that you're trying to stuff pointers into the objects (rather than into the top level array, as you are doing), in which case you want something like:
for(size_t j = 0; j < bs-1; j ++) { *(char **)p[j] = p[j + 1]); }
*(char **)p[bs-1] = 0; // null terminate the linked list
this assumes that obj is defined something like:
struct obj {
struct obj *next;
// more fields
Related
I have a List class for char arrays. And I want to push back N arrays from 'a' to 'a..a'.
char* x;
SList list;
for (unsigned int i = 1; i < n+1; i++) {
x = new char[i+1];
for (unsigned int j = 0; j < i; j++) {
x[j] = 'a';
}
x[i] = '\0';
list.push_back(&x);
}
But every time, x has the same address. And in result, my List object contains N pointers to the same address.
Is there a way to push back these arrays in loop with correct memory allocation?
Before asking found this question, but it doesn't provide a cool solution for my problem.
In each iteration of the loop x = new char[i+1]; returns a different address, which is stored in x. So the value of x changes in each iteration, yet, the address of x doesn't.
Did you mean
list.push_back(x);
to add the address of the newly allocated memory? Of course this would require you to change the type of list the a collection of char *.
It must be mentioned that dereferencing &x after x goes out of scope will lead to undefined behaviour, because x doesn't exist anymore. You fill list with dangling pointers.
Finally I'd like to mention that you could avoid the nasty manual memory management and simply use a std::vector<std::string>.
std::vector<std::string> list;
for (unsigned int i = 1; i < n+1; i++) {
std::string newString(i, 'a'); // string with i times 'a'
list.push_back(newString);
}
Ok. I found a pretty straightforward solution:
char** x = new char*[n];
SList sl;
for (unsigned int i = 0; i < n; i++) {
x[i] = new char[i+1];
for (unsigned int j = 0; j < i; j++) {
x[i][j] = 'a';
}
x[i][i] = '\0';
sl.push_back(&x[i]);
}
With having N addresses to store pointers to arrays. I can just add their addresses to my list object
So for a project I have i need to create a function to 'Resize' the first dimension of a dynamically allocated 3d array of shorts, the function cant alter the original data and must only alter the first dimension of the array.
3darray[alter this][stays the same][stays the same]
The variables passed into the function are the pointer that points to the 3d array, the old size, and the new size.
Ive tried this:
void reallocShort3d(short ***&ptr, size_t oldSize, size_t newSize)
{
short *** temp;
temp = (short***) realloc(ptr,(newSize - oldSize) * sizeof(ptr));
ptr = temp;
}
but it does not seem to be working, any idea on where i went wrong and possible solutions?
Thanks
EDIT: I realise that I can't use realloc now as th 3d array was created with new, we are only given the old and new sizes of the first dimension and the array itself, we are not allowed to use vectors:
/**
* #brief reallocates/resizes a 3D array of shorts to fit into a new size.
* Size here refers to the first dimension. i.e. ptr[size][row][col].
*
* #note after the function executed, the original data in the array must
* not be altered in any way. That is to say, only the first dimension of
* ptr may be altered.
*
* #NOTE! this function must work in general
*
* #param ptr is the pointer that refers to the 3D array to be resized.
* #param oldSize is the current total number of elements in the first
* dimension of ptr. e.g. ptr[this amount here][row][col]
* #param newSize is the new size that ptr will have after the function
* has been executed. ptr[the new amount here][row][col]
*/
SECOND EDIT:
Heres the code used to allocate the 3d array:
ptr = new short**[2];
for (int i = 0; i < 2; i++)
{
ptr[i] = new short*[12];
for (int j = 0; j < 12; ++j)
{
ptr[i][j] = new short[numDaysinMonth(j)];
}
}
Given the way OP's code allocates the memory, a simple way to resize it is:
short ***tmp;
// in OP's code rows = 12 while the inner dimension is the number of days in a month
// so we can use cols = 31
tmp = new short**[newSize];
// copy the old data
for ( size_t i = 0; i < oldSize; ++i ) {
tmp[i] = ptr[i];
}
// allocate memory for the new data
for ( size_t i = oldSize; i < newSize; ++i ) {
tmp[i] = new short*[rows];
for ( size_t j = 0; j < rows; ++j ) {
tmp[i][j] = new short[cols];
}
}
delete[] ptr;
ptr = tmp;
EDIT
The comment of #PaulMcKenzie points out a major flaw in this code. In C++, operator new throws an exception when it's unable to allocate the requested memory. If this happens, our options are limited and in most cases the only thing we can do is some clean up and exit the program.
In the following snippet I'll try to rewrite the function with OP's signature (which I personally, don't like) and to avoid the possible memory leaks. This function eventually rethrows a std::bad_alloc exception and it is up to the caller to deal with it (which, I'm pretty much sure, OP's code doesn't).
I'd like to remark that a far better practice would be to stick to the Standard Library containers and/or encapsulate all the memory managment in a class, to ensure RAII.
void reallocShort3d(short ***&ptr, size_t oldSize, size_t newSize, size_t rows, size_t cols ) {
short ***tmp = nullptr;
std::bad_alloc ee;
try {
tmp = new short**[newSize];
size_t i = 0, j = 0, ii, jj, kk;
for ( ; i < oldSize; ++i ) {
tmp[i] = ptr[i];
}
for ( ; i < newSize; ++i ) {
try {
tmp[i] = new short*[rows];
for ( j = 0; j < rows; ++j ) {
try {
tmp[i][j] = new short[cols];
}
catch ( const std::bad_alloc &e ) {
for ( jj = 0; jj < j; ++jj ) {
delete[] tmp[i][jj];
}
delete[] tmp[i];
throw e;
}
}
}
catch ( const std::bad_alloc &e ) {
for (ii = oldSize; ii < i; ++ii) {
for ( jj = 0; jj < rows; ++jj ) {
delete[] tmp[ii][jj];
}
delete[] tmp[ii];
}
delete[] tmp;
throw e;
}
}
delete[] ptr;
ptr = tmp;
}
catch ( const std::bad_alloc &e ) {
std::cout << "Error: unable to reallocate.\n";
throw e;
}
}
As alluded to in the comments, the signature of the reallocate function is not sufficient for the general case as one requires knowledge of the rows, cols and slices of the original 3D array to be able to perform reallocation.
So, assuming you can fix the method signature for the general case the following is a possible solution:
void reallocate_short_3d_arr(short***& ptr, std::size_t new_rows, std::size_t old_rows,
std::size_t cols, std::size_t slices) {
// allocate memory for tmp 3d arr
short*** tmp = new short**[new_rows];
for (std::size_t i = 0; i < new_rows; ++i) {
tmp[i] = new short*[cols];
for (std::size_t j = 0; j < cols; ++j)
tmp[i][j] = new short[slices];
}
// select correct rows for contraction or expansion of ptr
std::size_t tmp_rows = (new_rows > old_rows) ? old_rows : new_rows;
// copy all entries from ptr to tmp
for (std::size_t i = 0; i < tmp_rows; ++i) {
for (std::size_t j = 0; j < cols; ++j) {
for (std::size_t k = 0; k < slices; ++k)
tmp[i][j][k] = ptr[i][j][k];
}
}
// delete original ptr memory
for (std::size_t i = 0; i < old_rows; ++i) {
for (std::size_t j = 0; j < cols; ++j) {
delete[] ptr[i][j];
}
delete[] ptr[i];
}
delete[] ptr;
// assign ptr to tmp such that ptr points to reallocated memory
ptr = tmp;
}
One could probably optimise this via using std::move to assign the contents of ptr to tmp instead fairly trivially as the original ptr contents is deleted afterwards anyway so it is safe to move it.
Of course, this is all very silly C++ though and could be easily achieved via std::vector as follows:
std::vector<std::vector<std::vector<short>>> vec_3d(rows,
std::vector<std::vector<short>>(cols,
std::vector<short>(slices))); // initialise "3D vector" of dims rows*cols*slices
vec_3d.resize(new_rows); // resize just the rows, leaving slices and columns the same
Why does this happen?
u_char macDst[6], macSrc[6], ipType[2]={0x88, 0x92};
u_char header[] = {0x04,0x00,0x20,0x00,...,};
const int len = sizeof(macDst) + sizeof(macSrc) + sizeof(header) + 2;
u_char* pck[len];
int j = 0, length = sizeof(macDst);
for (j; j < length; j++)
{
pck[j] = &macDst[j];
}
length += sizeof(macSrc);
for (j; j < length; j++)
{
pck[j] = &macSrc[j - sizeof(macDst)];
}
pck[j++] = &ipType[0];
pck[j++] = &ipType[1];
length += sizeof(header) + 2;
for (j; j < len; j++)
{
pck[j] = &header[j - sizeof(macDst) - sizeof(macSrc)];
}
u_char testSend[170];
memcpy(testSend, *pck, sizeof(pck));
The var testSend only has macDst values (before initialized), while in the pointer I have all of them. If I copy them one by one, I get a good result:
for (int k = 0; k < 170; k++)
{
testSend[k] = *pck[k];
}
Any idea??
Thanks!!
Edit:
This is a physic problem:
-----ooooooooo------------aaaa----bbbb----
- Null Data
When I make the pointers array I am doing this:
oooooooooaaaabbbb
But when I sent the packet and when I did the memcpy (or memmove) I was saying this: take this pointer and this amount of memory and copy them:
----|oooooooooo----------|----aaaaa----bbbb----
being the amount the sum of the 3 memory places.
I find the code convoluted, and I would never write it this way. Still, the error here:
memcpy(testSend, *pck, sizeof(pck));
You are dereferencing pck - and point to the first element, which is a char*. This is what you copy using your memcpy. On the other hand, your hand-written loop does dereference the pointer before copying it.
Fill the testSend array directly:
u_char *p = testSend;
memcpy(p, macDst, sizeof(macDst)); p += sizeof(macDst);
memcpy(p, macSrc, sizeof(macSrc)); p += sizeof(macSrc);
memcpy(p, ipType, sizeof(ipType); p += sizeof(ipType);
memcpy(p, header, sizeof(header));
So my program executes as expected and prints out the correct result. The only issue is that after it is done it does not exit. If I wait a few more seconds windows pops up an error message saying "bignumbs.exe has stopped working". Here is the code to the new function which seems to be causing the problem.
void BigInt::u_basic_mult(const BigInt& n, int digs)
{
const base_int* tptr = n.used > used ? n.data : data;
const base_int* bptr = tptr == data ? n.data : data;
const int tlen = tptr == data ? used : n.used;
const int blen = bptr == data ? used : n.used;
if(digs < 1)
digs = tlen + blen + 1;
base_int* new_data = new base_int[digs];
for(int i = 0; i < digs; ++i)
*new_data++ = 0;
for(int i = 0; i < blen; ++i)
{
int stop_pt = MIN(tlen, digs - i);
overflow_int carry = 0;
overflow_int btmp = bptr[i];
for(int j = 0; j < stop_pt; ++j)
{
overflow_int prod = btmp * tptr[j] + carry;
carry = prod >> BASE_BITS;
overflow_int sum = new_data[i + j] + carry + (prod & MAX_DIG);
carry += sum >> BASE_BITS;
new_data[i + j] = sum;
}
}
//delete[] data; these two lines cause the error
//data = new_data;
used = digs;
alloc = digs;
strip_zeros();
}
Notice the two lines I commented out. Without them the program executes and finishes (although now the result is incorrect). What is it about changing the value of a pointer or deleting it which could make my program have this strange error? Also I am pretty sure data is valid since I use it in the code above.
Also I am compiling with G++ through Netbeans.
After inspecting further it seems that the problem may be with my deconstructor. If I comment out the delete[] data in the deconstructor the error seems to go away. I don't know why.
BigInt::~BigInt()
{
if(data) delete[] data;
}
for(int i = 0; i < digs; ++i)
*new_data++ = 0;
This code is modifying where the new_data pointer is pointing at, so that it is no longer pointing at the original array when you enter the subsequent loop, or do anything with it for that matter. The pointer you pass to delete[] must be pointing at the same memory address that new[] returned.
The correct way to zero-initialize the array is to do this instead:
for(int i = 0; i < digs; ++i)
new_data[i] = 0;
Or, get rid of the loop and just use memset() instead:
memset(new_data, 0, digs * sizeof(base_int));
You must be very careful about matching up uses of new and delete. If you allocate something using the array form of new, you must delete it using the array form of delete. If you mix-and-match the array and non-array forms, you'll get crashes like this. You also must never delete something that wasn't allocated with new, and you must never delete the same thing twice.
I can't give you any more specific advice about this particular program, because you do not show us where the pointer named data is allocated.
I got it. I managed to screw up my new_data pointer.
for(int i = 0; i < digs; ++i)
*new_data++ = 0;
I changed it to this.
for(int i = 0; i < digs; ++i)
new_data[i] = 0;
CASE1:
int nrows=5;
int ncols=10;
int **rowptr;
rowptr=new int*;
for(int rows=0;rows<nrows;rows++) {
for(int cols=0;cols<ncols;cols++) {
*rowptr=new int;
}
}
CASE2:
int nrows=5;
int ncols=10;
int **rowptr;
for(int rows=0;rows<nrows;rows++) {
rowptr=new int*;
for(int cols=0;cols<ncols;cols++) {
*rowptr=new int;
}
}
I am able to insert and print values using both ways. What is the difference in initializations?
What is the difference?
#1 just allocates memory enough to hold a integer pointer and not an array of integer pointers.
#2 Causes a memory leak by just overwritting the memory allocation of the previous iteration.
I am able to insert and print values using both the ways
Memory leaks and Undefined behaviors may not produce immediate observale erroneous results in your program but they sure are good cases of the Murphy's Law.
The correct way to do this is:
int nrows = 5;
int ncols = 10;
//Allocate enough memory for an array of integer pointers
int **rowptr = new int*[nrows];
//loop through the array and create the second dimension
for (int i = 0;i < nrows;i++)
rowptr[i] = new int[ncols];
You have a memory leak in both cases.
The proper way to initialize such a "2d" array is
int** arr = new int*[nrows];
for (int i = 0; i < nrows; i++)
arr[i] = new int[ncols];
Note however, that it isn't a 2d array as defined by C/C++. It may not, and probably will not, be consecutive in memory. Also, the assembly code for accessing members is different.
In your case, the accessing by indexing is equivalent to *(*(arr+i)+j)
And in the case of a 2d array it's *(arr + N_COLS*i + j) when N_COLS is a compile time constant.
If you want a true 2d array you should do something like this:
int (*arr)[N_COLS] = (int(*)[N_COLS])(new int[N_ROWS * N_COLS])
You'd better use 1d array to manage 2d array
int **x = new int*[nrows];
x[0] = new int[nrows*ncols];
for (int i = 1; i < nrows; i++)
x[i] = x[i-1] + ncols;
for (int i = 0; i < nrows; i++)
for (int j = 0; j < ncols; j++)
x[i][j] = 0;
delete [] x[0];
delete [] x;