I'm new to C++, and I've been trying to figure out how to access just 1 element in a 2D array that I've dynamically allocated like so:
char** array;
array = new char*[3];
for(int i = 0; i < 3; i++) {
array[i] = new char [3];
}
I've been trying to access it like this:
cout<< array[0][0];
Whenever I try to do this, nothing prints out and the program segfaults.
How should I fix it so that it prints?
Thank you for your time!
If you're looking to create a 2D array you should take a look at this Stack Overflow post here. It has a nice image to explain how 2D memory is laid out and how to properly create the array. Remember, when you create dynamic memory using new you need to delete the memory manually with delete[]. The second response gives a code example of how to delete the 2D array. Once you have your array you can access it by cout << array[x][y], where x and y are your row and column indices. I'd focus on properly creating the 2D array and understanding that first.
Related
I'm trying to use a linear search function on a dynamic array I created but then the teaching assistant for my computer science class told us that most search functions use const arrays.
Is there any way I can edit my dynamic array to become contant? Or is it also possible to make a search function that uses a dynamic array (and would not give errors?).
I'll give a brief insight into my code:
I dynamically create an array using the rows I read in from a file and then dynamically allocate each row to an array of columns.
char ** domain[] = new char * [rows];
for(int i = 0; i < rows; i++)
{
*domain = new char[columns];
domain++;
}
The type of function that we were taught for searching is:``
char searchArray( const char list[], char letter, int maxSize)
{
>code goes here
}
Is there any other method of using a search function that takes in dynamic multidimensional arrays?
In response to the comments, I can't use vectors. This is an assignment for us to use normal arrays. I haven't been taught how to to use vectors yet.
In the line
char ** domain[] = new char * [rows];
char ** domain[] tries to make an array of char **. If the compiler didn't complain about not having a valid array size in the [] and you would have a 3D structure. You want just plain old char ** for a 2D structure, so
char ** domain = new char * [rows];
The loop filling out the inner dimension is correct except it loses track of the starting point of domain
for(int i = 0; i < rows; i++)
{
*domain = new char[columns];
domain++;
}
Should be something like
char ** temp = domain;
for(int i = 0; i < rows; i++)
{
*temp = new char[columns];
temp++;
}
To preserve the starting point, but for this case array notation is probably the smarter and easier-to-read option.
for(int i = 0; i < rows; i++)
{
domain[i] = new char[columns];
}
On to searchArray. It needs to know it's getting two dimensions, (const char **) and that there are two max sizes (maxRow and maxColumn). It will look something like
char searchArray(const char ** list,
char letter,
int maxRow,
int maxColumn)
{
>code goes here
}
Code goes here is your problem, but will probably be two nested for loops iterating to maxRow and maxColumn and returning when letter is found.
But... Why return a char? Returning the location in the array is much more useful. We could use std::pair, but if std::vector is off limits, pair probably is as well. Consider something like the following instead:
struct coord
{
int row;
int column;
};
coord searchArray(const char ** list,
char letter,
int maxRow,
int maxColumn)
{
coord location;
>code goes here
return location;
}
If the item is not found, set row and column to something impossible to get like -1 so you can easily test for the not found case.
Stop here unless you want to <expletive deleted> with your teacher's brain.
The above doesn't build a 2D array. You can't get a dynamically allocated 2D array in C++. What you have is an array of arrays. There are a couple downsides to this, look at all the work that goes into stitching one together and computers love it when things go in straight lines. Array of arrays doesn't. Every different allocation can be somewhere completely different in memory forcing the program to hop around, waiting on and loading different chunks of memory. Sometimes The program will spend more time sitting around waiting for stuff to be found and loaded than it'll spend doing the actual work. This sucks.
The solution is to make a 1D array and make it look like a 2D array. Here's an example of that from the C++ FAQ
You'll learn a lot of neat stuff from following this example, not the least of which being RAII and the Rule of Three, two concepts without which you cannot write non-trivial high quality C++ code.
I have the following piece of code, which is only half on the entire code:
// Declare map elements using an enumeration
enum entity_labels {
EMPTY = 0,
WALL
};
typedef entity_labels ENTITY;
// Define an array of ASCII codes to use for visualising the map
const int TOKEN[2] = {
32, // EMPTY
178 // WALL
};
// create type aliases for console and map array buffers
using GUI_BUFFER = CHAR_INFO[MAP_HEIGHT][MAP_WIDTH];
using MAP_BUFFER = ENTITY[MAP_HEIGHT][MAP_WIDTH];
//Declare application subroutines
void InitConsole(unsigned int, unsigned int);
void ClearConsole(HANDLE hStdOut);
WORD GetKey();
void DrawMap(MAP_BUFFER & rMap);
/**************************************************************************
* Initialise the standard output console
*/
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hStdOut != INVALID_HANDLE_VALUE)
{
ClearConsole(hStdOut);
// Set window title
SetConsoleTitle(TEXT("Tile Map Demo"));
// Set window size
SMALL_RECT srWindowRect;
srWindowRect.Left = 0;
srWindowRect.Top = 0;
srWindowRect.Bottom = srWindowRect.Top + MAP_HEIGHT;
srWindowRect.Right = srWindowRect.Left + MAP_WIDTH;
SetConsoleWindowInfo(hStdOut, true, &srWindowRect);
// Set screen buffer size
COORD cWindowSize = { MAP_WIDTH, MAP_HEIGHT };
SetConsoleScreenBufferSize(hStdOut, cWindowSize);
}
/*************************************************************************/
/*************************************************************************
* Initialise the tile map with appropriate ENTITY values
*/
MAP_BUFFER tileMap;
for (unsigned int row = 0; row < MAP_HEIGHT; row++)
{
for (unsigned int col = 0; col < MAP_WIDTH; col++)
{
tileMap [row][col] = WALL;
}
}
Essentially the entire code is used to create a tile map and output it to screen but I'm attempting to make tileMap a dynamic array in runtime.
I have tried creating one down where the tileMap is being created.
I've tried creating one just after "entity_lables" are given the typedef "ENTITY".
I've tried creating one after the "MAP_BUFFER" and "GUI_BUFFER" become aliases.
But still I'm at a loss, I have no idea on how to successfully implement a dynamic array to tileMap, and I certainly don't know the best spot to put it.
Any help would be greatly appreciated.
The syntax you are using for defining your array is for a constant sized C array. In general you should shy away from C arrays unless the size of the data is determined at compile time(and never needs to change) and the array never leaves the scope(because a C array does not retain information on its own size.)
In place of constant or dynamically sized C arrays I would suggest to use the Vector container. The Vector is a dynamically sized container that fills up from the back, the last element you have added to
std::vector<std::vector<ENTITY>>
To add the vector container to your project add the line
#include <vector>
To fill the container your loop could look like:
MAP_BUFFER tileMap;
for (unsigned int row = 0; row < MAP_HEIGHT; row++)
{
std::vector<ENTITY> column; // A column of the tile map
for (unsigned int col = 0; col < MAP_WIDTH; col++)
{
column.push_back(WALL); // Add one element to the column
}
tileMap.push_back(column); // Add the column to the tile map
}
or you could initialize the Vector to the size you want at the beginning and use your current loop to assign the tile values:
using TILE_MAP = vector<vector<ENTITY>>;
// MAP_WIDTH x MAP_HEIGHT multidimensional vector
TILE_MAP tileMap(MAP_WIDTH, vector<ENTITY>(MAP_HEIGHT));
for (unsigned int row = 0; row < MAP_HEIGHT; row++)
{
for (unsigned int col = 0; col < MAP_WIDTH; col++)
{
tileMap [row][col] = WALL;
}
}
Calling an element of a vector after it has been filled has the same syntax as an array.
tileMap[2][4]
You can also check the length of the vector:
int rows = tileMap.size();
if( rows > 0 )
int columnsInRow0 = tileMap[0].size()
While you are at it you should look into other containers like Maps and Sets since they make your life easier.
Edit:
Since you want to know how to make a dynamic array not using a vector I will give you an answer: std::vector is the C++ defined dynamically sized array. C arrays will not change size after they are defined, vector will.
However I think you are asking about the ability to define runtime constant sized arrays. So I will explain what they are and why you should not use them.
When you define the C array you are probably getting a warning saying that the expression needs to be constant.
A C array is a pointer to the stack. And the implementation of the compiletime C array is that it needs to be a constant size at compile time.
int compiletimeArray[] = { 1, 2, 3 };
// turns out c arrays are pointers
int* ptr = compiletimeArray;
// prints 2
std::cout << compiletimeArray[1];
// prints 2
std::cout << ptr[1];
// prints 2
std::cout << *(compiletimeArray + 1);
// also prints 2
std::cout << *(ptr + 1); //move pointer 1 element and de-reference
Pointers are like a whiteboard with a telephone number written on it. The same kind of issues occur as with telephone numbers; number on whiteboard has been erased, number on whiteboard has changed, recipient does not exist, recipient changed their number, service provider running out of available numbers to give new users... Keep that in mind.
To get create a runtime constant sized array you need to allocate the array on the heap and assign it to a pointer.
int size = 4;
int* runtimeArray = new int[size]; // this will work
delete[] runtimeArray; // de-allocate
size = 8; // change size
runtimeArray = new int[size]; // allocate a new array
The main difference between the stack and heap is that the stack will de-allocate the memory used by a variable when the program exits the scope the variable was declared in, on the other hand anything declared on the heap will still remain in memory and has to be explicitly de-allocated or you will get a memory leak.
// You must call this when you are never going to use the data at the memory address again
// release the memory from the heap
delete[] runtimeArray; // akin to releasing a phone number to be used by someone else
If you do not release memory from the heap eventually you will run out.
// Try running this
void crashingFunction() {
while(true)
{
// every time new[] is called ptr is assigned a new address, the memory at the old address is not freed
// 90001 ints worth of space(generally 32 or 64 bytes each int) is reserved on the heap
int* ptr = new int[90001]; // new[] eventually crashes because your system runs out of memory space to give
}
}
void okFunction() {
// Try running this
while(true)
{
// every time new[] is called ptr is assigned a new address, the old is not freed
// 90001 ints worth of space is reserved on the heap
int* ptr = new int[90001]; // never crashes
delete[] ptr; // reserved space above is de-allocated
}
}
Why use std::vector? Because std::vector internally manages the runtime array.
// allocates for you
vector(int size) {
// ...
runtimeArray = new runtimeArray[size];
}
// When the vector exits scope the deconstructor is called and it deletes allocated memory
// So you do not have to remember to do it yourself
~vector() {
// ...
delete[] runtimeArray;
}
So if you had the same scenario as last time
void vectorTestFunction() {
// Try running this
while(true)
{
std::vector<int> vec(9001); // internally allocates memory
} // <-- deallocates memory here because ~vector is called
}
If you want to use a runtime constant array I suggest the std:array container. It is like vector in that it manages its internal memory but is optimized for if you never need to add new elements. It is declared just like vector but does not contain resizing functions after its constructor.
In SO question [How to allocate a 2D array of pointers in C++] [1], the accepted answer also makes note of the correct procedure of how to de-allocate and delete said array, namely "Be careful to delete the contained pointers, the row arrays, and the column array all separately and in the correct order." So, I've been successfully using this 2D array in a cellular automaton simulation program. I cannot, however, get this array's memory management correct. I do not see an SO answer for how to do this other than the reference above.
I allocate the 2D array as follows:
Object*** matrix_0 = new Object**[rows];
for (int i = 0; i < rows; i++) {
matrix_0[i] = new Object*[cols];
}
My futile attempt(s) (according to Valgrind) to properly de-allocate the above array are as follows:
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
matrix_0[i][j] = NULL;
}
}
delete [] matrix_0;
matrix_0 = NULL;
Clearly, I'm missing the rows and cols part as reference [1] suggests. Can you show me what I'm missing? Thanks in advance.
[1]: (20 Nov 2009) How to allocate a 2D array of pointers in C++
You have a tonne of deleting to do in this:
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
delete matrix_0[i][j]; // delete stored pointer
}
delete[] matrix_0[i]; // delete sub array
}
delete [] matrix_0; //delete outer array
matrix_0 = NULL;
There is no need to NULL anything except matrix_0 because they are gone after delete.
This is horrible and unnecessary. Use a std::vector and seriously reconsider the pointer to the contained object.
std::vector<std::vector<Object*>> matrix_0(rows, std::vector<Object*>(cols));
Gets what you want and reduces the delete work to
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
delete matrix_0[i][j]; // delete stored pointer
}
}
But SergeyA's suggestion of storing unique_ptr, std::vector<std::vector<std::unique_ptr<Object>>> matrix_0; reduces the deletions required to 0.
Since speed is one of OP's goals, there is one more improvement:
std::vector<std::unique_ptr<Object>> matrix_0(rows * cols);
Access is
matrix_0[row * cols + col];
This trades a bit of visible math for the invisible math and pointer dereferences currently going on behind the scenes. The important part is the vector is now stored as a nice contiguous block of memory increasing spacial locality and reducing the number of cache misses. It can't help with the misses that will result from the pointers to Objects being scattered throughout memory, but you can't always win.
A note on vector vs array. Once a vector has been built, and in this case it's all done in one shot here:
std::vector<std::unique_ptr<Object>> matrix_0(rows * cols);
all a vector is is a pointer to an and a couple other pointers to mark end and the the location of the last location used. Access to the data array is no different from access to a dynamic array made with new. Using the index operator [] compiles down to data_pointer + index exactly the same as using [] on an array. There is no synchronizing or the like as in Java's Vector. It is just plain raw math.
Compared to a dynamic array all a preallocated vector costs you is two pointers worth of memory and in return you get as close to no memory management woes as you are likely to ever see.
Before setting the pointers to NULL, you should delete them first. After every pointer in the column are deleted, you can delete[] the row and set it to NULL, as every element is deleted and gone.
I'm trying to create a Pointer to a dynamic 3D Array full of Pointers. I'm working with Voxel, so let's say that t_cube is my object.
First, I tried doing this:
t_cube* (*m_Array)[][][];
I thought I could do like
m_Array = new t_cube[sizeX][sizeZ][sizeY];
Compiling this failed, however.
Next I tried this:
t_cube *(m_Model[]); // This is my .h
{
t_cube *model_Tempo[sizeX][sizeZ][sizeY]; // And this is in my class constructor.
m_Model = model_Tempo;
}
Again, this failed to compile.
I hope this example would be helpful to solve your problem:
Since, we are dealing with Pointer of 3-D Array. So, if I write it in C++ grammar, it would be like:
t_cube *array[x_size][y_size][z_size];
But, you already mentioned, it fails to execute.
Now, do the same thing using Dynamic Allocation Approach.
t_cube ****array; // Since, it a pointer to the 3D Array
array = new t_cube ***[x_size];
for(int i=0; i<x_size; i++) {
array[i] = new t_cube **[y_size];
for(int j =0; j<y_size; j++) {
array[i][j] = new t_cube *[z_size];
}
} /* I'm sure this will work */
And, the reasons you were facing trouble:
The size of the m_Array could be very large : x_size * y_size * z_size * sizeof(t_cube) .
You must have defined m_Array locally (inside the function), which is the major reason of program malfunction.
I am writing a program to simulate a cache in c++ and am trying to copy addresses that are given in a file into an array. I am struggling to figure out how to copy an array into another array so that I can have an array of memory address arrays. I have read in the addresses into an array called "address" and I want my simulated cache to be an array called "L1_Cache". h is a counter that I am incrementing after I put an address into the L1_Cache. Also, cache size is going to be how many lines of addresses are available in my L1_Cache array, which will be decided by the user of the program. Below is the snippet where I am trying to put the array into the other array.
if(sizeof(L1_Cache) < cachesize)
strcpy(L1_Cache[][h], address);
they are defined as:
const char* address[10];
char* L1_Cache;
If anyone has any suggestions on how to copy one array into another array to make an array of arrays, let me know. I am not sure if anything I am doing is correct, but I am struggling to figure this out.
I want to compare new addresses that I am given to old addresses that are already in the L1_Cache array.
Yes, it is possible to make an array of arrays.
int a[3][3]; // a is an array of integer arrays
You have
a[0]; // this refers to the first integer array
a[1]; // this refers to the second array
Is the following what you are looking for?
#include <iostream>
#include <cstring>
int main()
{
char p[2][256];
strncpy(p[0], "This is my first address", 256);
strncpy(p[1], "This is my second address", 256);
std::cout << p[0] << std::endl << p[1];
return 0;
}
Yes. They are called multidimensional arrays.
They can have any number of dimensions.
For example:
int foo[3][3]; // initialize the 2 dimensional array of integers
foo[0][0] = 1; // change a value
foo[0][1] = 2; // change a value
foo[0][2] = 3; // change a value
foo[1][0] = 4; // change a value
foo[1][1] = 5; // change a value
foo[1][2] = 6; // change a value
foo[2][0] = 7; // change a value
foo[2][1] = 8; // change a value
foo[2][2] = 9; // change a value
for(int i=0;i<3;++i){ // display the 2d array
for(int j=0;j<3;++j){
cout<<foo[i][j];
}
cout<<endl;
}
What's happening:
Values are being assigned in a chart.
Think of it like writing a value on each point of a piece of paper.