How to dynamically allocate an 2d array to a struct - c++

I'm trying to dynamically allocate an array on the heap using a structure that has a pointer to an array and a string. Here's my code.
struct StudentRecords
{
string names;
int* examsptr;
};
void main()
{
const int NG = 5;
string names[] = { "Amy Adams", "Bob Barr", "Carla Carr",
"Dan Dobbs", "Elena Evans"
};
int exams[][NG] =
{
{ 98,87,93,88 },
{ 78,86,82,91 },
{ 66,71,85,94 },
{ 72,63,77,69 },
{ 91,83,76,60 }
};
StudentRecords *data = nullptr;
(*data).examsptr = new int[][NG];
int *data = new int[NG*NG];

There's a number of problems with your current code.
StudentRecords *data = nullptr; //here you set data to nullptr
(*data).examsptr = new int[][NG]; //then you dereference nullptr, BAD
int *data = new int[NG*NG]; //then you declare another variable with the same name, BAD
You should rename one of your variables and set student records to an actual instance of StudentRecords.
You can't dynamically allocate a 2D array in one step like 'new int[rows][cols]'. Instead you either need to allocate a 1D array with rows*cols elements and do maths to convert a row and col into an index of the 1D array or you need to allocate an array of pointers, where each pointer points to an array holding the data. To hold the array of pointers you need a pointer to a pointer, so you need to make examsptr an int**.
You then need to allocate the arrays that are pointed at by the array of pointers in a loop.
EG:
//cant be nullptr if you want to dereference it
StudentRecords *data = new StudentRecords();
//data-> is shorthand for (*data).
//allocates array of pointers, length NG
data->examsptr = new int*[NG]
//now make the 2nd dimension of arrays
for(int i = 0; i < NG; ++i){
data->examsptr[i] = new int[NG];
}

Related

How to allocate and deallocate an array of function pointers and keep valgrind happy?

How can I allocate and deallocate an array of function pointers in C++? I've tried two different strategies, first using single pointers and the second using double pointers but I can't seem to make valgrind happy. Here is my situation:
// function pointer
typedef double(*function_ptr)(double);
// function that adhers to the interface set by function_ptr
double do_nothing(double x) {
return x;
}
// dynamically create array of #param size function pointers, all pointing to do_nothing
function_ptr **make_function_ptr(int size) {
function_ptr xp = &do_nothing_transform;
function_ptr* xpp = &xp;
auto **trsfm = (ESfcnTrsfm **) malloc(sizeof(function_ptr *));
for (int i = 0; i < size; i++) {
trsfm[i] = (ESfcnTrsfm*) malloc(sizeof(function_ptr));
trsfm[i] = xpp; // same as trsfm[i] = ...
}
return trsfm;
}
// free the array of function pointers
void free_function_ptr(function_ptr **fun, int size) {
for (int i=0; i<size; i++){
free(fun[i]);
fun[i] = nullptr;
}
free(fun);
fun = nullptr;
}
Your make_function_ptr function allocates space for only one function_ptr in the 'outer' table, rather than allocating space for size pointers. So, this:
auto **trsfm = (ESfcnTrsfm **) malloc(sizeof(function_ptr *));
Should be:
auto **trsfm = (ESfcnTrsfm **) malloc(sizeof(function_ptr *) * size); // Need to multiply by "size"
Without this, the trsfm[i] access in the subsequent for loop is undefined behaviour, when i is anything other than zero.
Furthermore (as pointed out in the comments), you are allocating memory in that for loop unnecessarily. You need only assign the address of the dummy routine to the allocated table entries:
for (int i = 0; i < size; i++) {
// trsfm[i] = (ESfcnTrsfm*) malloc(sizeof(function_ptr)); // Unnecessary!
trsfm[i] = xpp; // same as trsfm[i] = ...
}
(And, similarly, you don't need the for loop to free those pointers in your free_function_ptr function.)
This line is obviously wrong:
auto **trsfm = (ESfcnTrsfm **) malloc(sizeof(function_ptr *));
You need to allocate that multiplied by "size".

Segmentation fault - new and delete have been used. Lots of arrays are being created during runtime (unbounded array)

I'm trying to implement an unbounded array: What is an unbounded array?
More details on this page:
http://www.cs.cmu.edu/~fp/courses/15122-s11/lectures/12-ubarrays.pdf
This is the code:
#include <iostream>
#include <cstdlib>
using namespace std;
class UBArray
{
public:
int *arr, *arrN, j, *pos; //Initial array is arr. The position of arr is stored in pos. arrN is the new array created when size = limit.
int size, limit; //size is the current size of the array and limit is the total size available untill a new array is created.
UBArray()
{
size = 0;
limit = 10;
arr = new int[10];
pos = arr;
}
private:
void increment()
{
// New array arrN is created and then the values in the old arrays is put into the new array.
// Limit is increased by 10 - this is the extra space the new array contributres.
// pos which carries the address of the current array now carries the address of the new array.
// Later when a new array is created its address will be on the heap which is empty. This address is replace the address stored
// in the arrN. The older array can still be accessed for the array updation process by using the variable pos.
// IMPORTANT: I had initially tried to delete the older array to space space but while trying to debug the segmentation fault, I have
// removed it. I will be adding it again once the error has been fixed.
arrN = new int[size + 10];
for (j = 0; j < size; j++)
{
arrN[j] = pos[j];
}
limit = limit + 10;
pos = arrN;
}
public:
void push(int n)
{
if (size<limit)
{
size++;
pos[size-1]=n;
}
else
{
increment();
push(n);
}
}
int pop()
{
int p = pos[size-1];
size--;
return p;
}
};
int main()
{
UBArray array;
int num;
cout << "Enter 36 elements: ";
for (int k = 0; k<36; k++)
{
cin >> num;
array.push(num);
}
cout << endl << "The last element is : " << array.pop();
}
I have tried to give comments in the code to make it understandable to the reader. I'm copying some of it here:
Initial array is arr. The position of arr is stored in pos. arrN is the new array created when size = limit.
size is the current size of the array and limit is the total size available until a new array is created.
New array arrN is created and then the values in the old array are put into the new array.
Limit is increased by 10 - this is the extra space the new array contributres.
pos which carries the address of the current array now carries the address of the new array.
Later when a new array is created its address will be on the heap which is empty. This address is replaced the address of arrN. The older array can still be accessed for the array updation process by using the variable pos which will be updated by the old values have been copied to the new one.
I get segmentation fault during execution. I have tried to use cout statements to debug the code but it seems really confusing. I could see loops both inside and outside the for loop inside the increment method. I'm unable to figure out much. Any help is appreciated.
UPDATE: As pointed out by jrok, I changed the code and the seg fault is gone. But I'm getting seg fault again at the creation of the 3rd array.
UPDATE 2 Everything fixed now. Thank you.
arr = new int(10*sizeof(int));
That creates a single int, initialized to the value of 10*sizeof(int). The loop you wrote right after this statement runs out of bounds and it's cause of segmentation fault.
What you want is the array form of new:
arr = new int[10]; // note 10 only, new expression knows the size
// of the type it allocates
Note that when you assign the pointer to the new array to the pointer to the old array you lose the handle to it and create a memory leak:
int* arr = new int[10];
int* new_arr = new int[20];
arr = new_arr; // original array at arr has leaked
You need to delete[] arr before you reassign it. Also, I see no use for the third (pos) pointer. Not even for arrN, for that matter. One will do. Create a local pointer inside increment and assign it to arr when you're done deallocating the old array.
Finally, what people have been telling you in the comments, unless this is a learning exercise, don't try to reinvent the wheel and use std::vector instead.
An unbounded array only needs 3 data members (rather than 6): the address of the beginning of the data buffer, the capacity of the buffer, and the actual size (of the part of the buffer used so far). When expanding, you will temporarily need to hold the address of the new buffer in an automatic variable. Also, you should avoid leaking the memory of previous buffers. A simple layout is like this:
struct ua
{
int size,capacity,*buff; // 3 data members only
ua(int n) // constructor: n = initial capacity
: size(0) // initially empty
, capacity(n<0?0:n) // guard against n<0
, buff(capacity?new int[capacity]:0) {} // only allocate if n>0
~ua() { delete[] buff; } // destructor: note: delete[] 0 is ok
void empty() const { return size==0; } // is array empty?
void push(int x) // add another datum at back
{
if(size==capacity) { // buffer is full: we must expand
if(capacity) capacity+=capacity; // double capacity
else capacity=1; // but ensure capacity>0
int*nbuff=new int[capacity]; // obtain new buffer
if(size)
memcpy(nbuff,buff,size*sizeof(int)); // copy data from old to new buffer
delete[] buff; // free memory form old buffer
buff=nbuff; // set member buff to new buffer
}
buff[size++]=x; // write; increment size (post-fix)
}
int pop() // ill-defined if empty()
{ return buff[--size]; } // read; decrement size (pre-fix)
int operator[](int i) const // ill-defined if i<0 or i>=size
{ return buff[i]; }
int&operator[](int i) // ill-defined if i<0 or i>=size
{ return buff[i]; }
// you may add more functionality, for example:
void shrink(); // reduces capacity to size
void reserve(int n); // extends capacity to n, keeping data
ua(ua const&other); // copy buffered data of other
void swap(ua&other); // swap contents with other (no copying!)
};

realloc pointer change when out of function

i am starting homework about dynamic array, first, I have a 2 dimensional array :
int initializeInfo[3][4] ={{77,68,0,0},{96,87,89,78},{70,90,86,0}};
and use pointer to store it:
int **ptr = (int**)malloc(3*sizeof(int));
int size = 0;
for(int i =0;i<3;i++){
addInitiazeInfo(ptr,initializeInfo[i],size);
}
here is function addInitiazeInfo:
void addInitiazeInfo(int**& ptr, int arr[],int& size){
ptr[size] = (int*)malloc(4*sizeof(int));
if(ptr[size] == NULL){
return;
}
ptr[size] = arr;
size++;
}
It's run OK! The 2 dimensional array is store by ptr pointer.
And I want to add new row, I think realloc is needed, then I try:
int arr[] = {3,4,5,6};
size++;
ptr = (int**)realloc(ptr,size * sizeof( int ) );
ptr[size-1] = (int*)malloc(4*sizeof(int));
ptr[size-1] = arr;
But I think this is my trouble, the output make me hard to know how it happend:
please help me, thanks everyone
When you do
ptr[size] = arr;
You are essentially assigning the address of arr, to ptr[size]. This means that the memory you just allocated is lost and successfully leaked.
You want to manually copy element by element or use something like memcpy. It is likely this might fix your issue, depending on the rest of your code.

Initializing Dynamic Array of Strings (C++)

I am working on assignment to create a container class for a dynamic array of strings. I know that it would be much easier/better done with std::vector, but that is not the point. I am having a problem finding the right way to initialize my array in the constructor. The way it is below, I am still being warned by the compiler that the variable lineArray is not used. The program compiles with a warning that lineArray is unused then hangs at runtime.
MyBag::MyBag()
{
nLines = 0;
std::string lineArray = new std::string[0] ();
}
void MyBag::ResizeArray(int newLength)
{
std::string *newArray = new std::string[newLength];
//create new array with new length
for (int nIndex=0; nIndex < nLines; nIndex++)
{
newArray[nIndex] = lineArray[nIndex];
//copy the old array into the new array
}
delete[] lineArray; //delete the old array
lineArray = newArray; //point the old array to the new array
nLines = newLength; //set new array size
}
void MyBag::add(std::string line)
{
ResizeArray(nLines+1); //add one to the array size
lineArray[nLines] = line; //add the new line to the now extended array
nLines++;
}
http://ideone.com/pxX18m
You are using a local variable called lineArray in your constructor. You want to use your data member, for example:
MyBag::MyBag()
{
nLines = 0;
lineArray = new std::string[0] ();
}
In addition to the obvious error reported by compiler (i.e. initializing a local variable rather than assigning to an instance variable) you have a more serious issue: if a value smaller than nLines is passed to ResizeArray, your code would exhibit undefined behavior by writing data past the end of the allocated region. You need to change the code as follows:
void MyBag::ResizeArray(int newLength)
{
// Add a trivial optimization:
if (newLength == nLines) {
// No need to resize - the desired size is already set
return;
}
std::string *newArray = new std::string[newLength];
//create new array with new length
for (int nIndex=0; nIndex < nLines && nIndex < newLength ; nIndex++)
{ // ^^^^^^^^^^^^^^^^^^^^^
newArray[nIndex] = lineArray[nIndex];
//copy the old array into the new array
}
delete[] lineArray; //delete the old array
lineArray = newArray; //point the old array to the new array
nLines = newLength; //set new array size
}
Warning to the rescue. Good thing that you had compiler warnings otherwise this would have been a bug which will have taken longer to figure out.
std::string lineArray = new std::string[0] ();
^^^^^^^^^^^
is declaring a new variable called lineArray with in the constructor. You are not using the class member one. The member lineArray pointer will still be pointing to some uninitialized memory.
It should be
lineArray = new std::string[0] ();
In addition to the shadowed member variable, and the ResizeArray to smaller array issue, there is a bug in your add() method, as indicated by 6602. After your call to ResizeArray, nLines has already been updated to the new value, so you are actually writing to the wrong array position, and then wrongly incrementing nLines again. Make sure to write to the correct position, and there is no need to increment.
void MyBag::add(std::string line)
{
int oldLength = nLines;
ResizeArray(nLines+1); //add one to the array size
lineArray[oldLength] = line; //add the new line to the now extended array
}

VC++: Pass multiple arrays between functions

I'm quite new to VC++, and I need to pass 4 arrays between functions, so I'm using another array to store their pointers. Have I done it correctly?
unsigned int* step1(...) {
...
// save data arrays
unsigned int* savedData = new unsigned int[4];
savedData[0] = *data0;
savedData[1] = *data1;
savedData[2] = *data2;
savedData[3] = *data3;
return savedData;
}
unsigned char* step2(unsigned int* savedData, ...) {
// read data arrays
unsigned int* data0 = &savedData[0];
unsigned int* data1 = &savedData[1];
unsigned int* data2 = &savedData[2];
unsigned int* data3 = &savedData[3];
...
}
In order to complete the previous valid answers, I will try to expand the answer:
Have I done it correctly?
Well, in order to pass data between functions: yes, doing it with pointers is an option. But it is commonly discouraged by the community because it makes troublesome the memory management.
When you work with pointers pointing dynamic memory, you must have a clear image of WHERE the memory is created and WHERE the memory will be deleted, in other words: the cycle of life of the memory must be clear and straightforward and for this reason, pass pointers between functions is commonly discouraged.
For example, in your case: the unsigned int* step1(...) function returns a pointer but looking at it, a new programmer or someone that works with you wouldn't tell if the pointer returned is dynamic memory and if calling step1 must delete or delete [] the memory after the call, same goes for unsigned char* step2(unsigned int* savedData, ...) and would be more confusing and troublesome because someone would ask: step2 would alter the savedData passed?
In order to fix the step2 issue, you can change the function to:
unsigned char* step2(const unsigned int* const savedData, ...)
By adding the const you're telling: "Hey! step2 isn't going to alter the contents of savedData nor changing the address it is pointing to".
But all the previous text is useless because doesn't fix the most important problem: Where the memory is freed?
In the step1 you're creating memory dynamically, in the step2 this memory is readed but... the delete is hidden somewhere in the code that you don't paste? or there is a step3 waiting for take care of the memory?
To avoid all this memory headaches, is commonly advised the use of STL containers, like std::vector, the container will take care of the memory management for you, in your case:
typedef std::vector<int> intvector;
typedef std::vector<intvector> intintvector;
void step1(intintvector &Data, ...) {
...
// create data arrays
intvector data0, data1, data2, data3;
// fill data0, data1, data2, data3
// ...
// save data arrays.
Data.push_back(data0);
Data.push_back(data1);
Data.push_back(data2);
Data.push_back(data3);
}
void step2(const intintvector &savedData, ...) {
// read data arrays
intvector data0 = savedData[0];
intvector data1 = savedData[1];
intvector data2 = savedData[2];
intvector data3 = savedData[3];
// ...
}
In brief summary: You aren't using correctly the pointer part if you don't take care of the dynamic memory, so, you must fix this issue or delegate into STL containers.
Hope it helps! :D
Use std::vector.
std::vector<int> data;
data.push_back(data0);
data.push_back(data1);
data.push_back(data2);
data.push_back(data3);
And
int data0 = data[0];
int data1 = data[1];
int data2 = data[2];
int data3 = data[3];
And add some code, where these functions will be used.
You will need an array of pointers, for example:
//The function that takes the array
void foo( char ** data )
{
std::cout << data[0];
std::cout << data[1];
std::cout << data[2];
}
main()
{
char * str = "aaa";
char * str1 = "sss";
char * str2 = "ddd";
char ** res = new char *[3];//here's your array that has 3 elements each of which is a pointer.
res[0]=str;
res[1]=str1;
res[2]=str2;
foo( res );
return 0;
}
The output will be
aaasssddd
A slightly better way:
It would be better to use stl containers instead of raw pointers since they are easier and safer to use. With pointers, it will work the same way:
void foo( std::vector< char * >vec )
{
std::cout << vec[0];
std::cout << vec[1];
std::cout << vec[2];
}
main()
{
char * str = "aaa";
char * str1 = "sss";
char * str2 = "ddd";
std::vector< char * >vec;
vec.push_back(str);
vec.push_back(str1);
vec.push_back(str2);
foo( vec );
return 0;
}
A further improved way:
And finally, the best way is to use strings:
void foo( std::vector< std::string >vec )
{
std::cout << vec[0];
std::cout << vec[1];
std::cout << vec[2];
}
main()
{
std::string str = "aaa";
std::string str1 = "sss";
std::string str2 = "ddd";
std::vector< std::string >vec;
vec.push_back(str);
vec.push_back(str1);
vec.push_back(str2);
foo( vec );
return 0;
}
Assuming you really want what you've written in question (4 arrays grouped into one), first of all you need 4 arrays, for example int:
int data1[] = {1,2,3,4};
int data2[] = {5,6,7,8,9,10};
int *data3; // Let's say those two were allocated by malloc/new
int *data4;
// Now array that will contain those values
int **data = new (int*)[4]; // int * = your datatype (array of ints)
// (int*)[] = array of arrays of ints
data[0] = data1;
data[1] = data2;
data[2] = data3;
data[3] = data4;
// And reverse function
data1 = data[0];
data2 = data[1];
data3 = data[2];
data4 = data[3];
Few notes:
if you want to have those "arrays" resizeable use (or use more than 4 items after time) use std::vector or another STL Container
if those data chucks have any special meaning (like data1 = user ids, data2 = visitor ids, ...) build class or structure that will name them:
// In C:
struct user_data{
int *user_ids;
int *visitor_ids;
char **unregistered_user_names; // Feel free to use another types
}
// In C++
class UserData {
std::vector<int> userIds;
std::vector<int> visitorIds;
std::vector<std::string> unregisteredUserNames;
}
Once allocated data with new unsigned int [4] don't forget free memory with delete [] array
I tried Vyktor's solution but it didn't work. I finally got it working using plain ol' arrays (no STL/vectors) and using the following code to save/load arrays from another parent array.
Note that this approach is considered "legacy" since you have to unallocate the arrays manually using the delete [] myArray syntax.
unsigned int** step1(...) {
...
// save data arrays
unsigned int** savedData = new unsigned int*[4]; // ** means pointer to a pointer
savedData[0] = data0; // transfer the pointer value straight
savedData[1] = data1;
savedData[2] = data2;
savedData[3] = data3;
return savedData;
}
unsigned char* step2(unsigned int** savedData, ...) { /// input is pointer to pointer
// read data arrays
unsigned int* data0 = savedData[0]; // read pointer straight
unsigned int* data1 = savedData[1];
unsigned int* data2 = savedData[2];
unsigned int* data3 = savedData[3];
...
}