Quick background, I have some experience with java and currently new to c++.
My question comes from an assignment in which we had to create 4 different magic squares, but for the nature of this particular question they can be any 2d array, so long as they are "exact" in values, only that they appear differently from each one. What I mean by that is if one 2d array looked like:
1 2 3
4 5 6
7 8 9
the next one would be rotated 90 degrees
7 4 1
8 5 2
9 6 3
and so on..
To make the first matrix I simply made a 2d array and created it using the magic square algorithm (irrelevant)
int** square = new int*[size]();
for (int i = 0; i<size; i++) {
square[i] = new int[size]();
}
//set values to square .. irrelevant to show, could be anything
//way down the code
int** secondSquare = square;
For the second third and fourth ones all I would need to do is rotate the previous one to get the next rotated square. My problem however wasn't that I could not flip the arrays, but that while trying to flip them the values for the first square were also changing.
Obviously this is more of a problem about being able to access the data in square and not change it while trying to add them to secondSquare.
I tried making it so square was a modifiable pointer w constant unmodifiable values.
const int** square = new int*[size];
The problem with this is that I have to assign values after to square so this cannot be done. Also when I initialize secondSquare it gives me an error since it is of type int** and not const int**.
Any better ways to handle problems with accessing data without changing values and setting both arrays (or objects really) properly on initialization?
You would do well to avoid using raw pointers and new entirely . That should really come in the advanced section of any C++ course.
Here is one way:
array< array<int,3>, 3> square = {{ {1, 2, 3}, {4, 5, 6}, {7, 8, 9} }};
square[1][1] = 12; // optional
const auto &c_square = square;
Now c_square is a const accessor of square that you can use later and avoid risk of modifying square.
The problem is int** secondSquare = square; copies the address of the square pointer to secondSquare. So in the end you have two (three, four) pointers pointing to exact same place in memory. Think about it like you have one square created but you try to access it through four different pointers.
What you want to do is to allocate memory for 4 different int** pointers.
To create a 2d array, you would declare it as const:
const int array_2d[3][3] =
{
0, 1, 2,
3, 4, 5,
6, 7, 8
};
In my experience, the better method is to declare it as static const so you are telling the compiler that there is only 1 read only instance:
static const int array_2d[3][3] =
{
0, 1, 2,
3, 4, 5,
6, 7, 8
};
The static allows for the compiler to place the data in a read-only section of the executable and access it directly, rather than copying it from Read-Only to the stack before usage (I've seen compilers emit this kind of code).
Related
I just wanted to know why are some arrays written like this?
int arr[] = {3, 4, 6, 9, 11};
Why can't it just be written like this instead?
int arr[5] = {3, 4, 6, 9, 11}
What's the benefit?
Why can't it just be written like this instead?
The premise is wrong. It can be written both ways.
What's the benefit?
The size is redundant information. We've already implicitly given the size 5 by providing 5 initialisers. Providing redundant information is a potential source of bugs during development when that information accidentally goes out of sync.
For example, if the programmer decides later that the last 11 wasn't supposed to be there and should be removed leaving 4 elements in the array, the programmer making that change might not notice that the size has to also be changed, leading to a case where the last element is not removed as intended but replaced with value initialised element instead.
If the size of the array is supposed to be the same as the number of initialisers, then it is safer to not specify that size explicitly. To not specify the size explicitly is to follow the "Don't Repeat Yourself" principle.
On the other hand, if the size of the array is always supposed to be 5 regardless of the number of initialisers, then specifying the size explicitly achieves that. I suspect that this case is rarer in practice (except when there are no initialisers at all). Note that you should probably use a constant variable instead of a magic number for the size.
When you don't write any number into brackets, it means the array will have size equal to count of elements intialized with.
When you put there some number, you are giving the array a size.
int arr[] = {1, 7, 5}; // Size of the array is 3
int arr[3] = {1, 7, 5}; // Size of the array is 3
int arr[5] = {1, 7, 5}; // Size of the array is 5
Declaring with defined size is good when you know that you will need this count of items, but you don't have the items yet.
Without defined size it is simply easier to write.
I've seen bunch of tutorials and threads, but no-one does this to resize an array. My question is, whether this affects bad something in my program or is there better way to resize it?
//GOAL:Array to become {1,2,4,5,6,7,8,9}
int size=9;
int array[size] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
for (int i = 2; i < 8; ++i)
array[i] = array[i + 1];
//ARRAY IS NOW{1, 2, 4, 5, 6, 7, 8, 9, 9}
//GOAL: TO DELETE THAT LAST 9 FROM ARRAY
size=8;
array[size];
//IT SHOULD BE {1,2,4,5,6,7,8,9} now, but does it effect my program in any negative context?
int array[size] declares an array of size elements.
Outside of a declaration, array[size] access element size in array. It does not resize the array. If you do something like that without changing the value of size, it actually tries to access the element after the last element in the array; not a good idea. In this case, since you changed size to be one less than the original, it accesses the last element of the array, which is safe but does not do what you want.
You can not resize an array in C/C++ that is declared on the stack (one allocated on the heap with malloc could be reallocated to a different size, but you'd have trouble copying it as the newly allocated array of the new size is possibly at a completely different memory location; you'd have to save the old one, allocate a new one of the new size, copy the elements you want, and then free the old one.)
If you want something resizeable, you are in C++; use a container (vector, for example, but pick the one that most suits your needs).
And....I just saw arnav-borborah's comment; don't know how I missed that. You can't even declare the array like that, as size is not a compile time constant.
Until size variable is not constexpr, this
int size=9;
int array[size] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
is Variable length array, which is not part of c++ standard, only extension of some compilers.
Also automatic arrays are not resizeable, they have fixed size since declaration until they goes out of scope.
You should use some STL container, like std::array, std::vector.
std::array needs to know size at compile time, so there is the best approach, std::vector, which is easy to use and resizeable.
// #include<vector>
std::vector<int> array { 1,2,3,4,5,6,7,8,9 }; // Uniform initialization
// Remove last element
array.pop_back(); // 'array' has now only 8 elements (1..8)
EDIT
As mentioned in comments, if you want to remove n-th element in vector, you may do
array.erase(array.begin()+n);
and job is done.
Hugely. say if you have a payload of 1GB and you Array.Resize the destination array in chunks of 10k then most of your application CPU and wait states will be resizing that array.
If you pre-allocate the array to 1GB, populating that array will be orders of magnitude faster. This is because every time you use Array.Resize.
The computer needs to move that memory in its entirety to another location in memory just to add the extra length you resized it by.
But of cause if you are dealing with very small arrays. This effect is not noticeable.
I'm fairly new to dynamic arrays, especially mullti-dimensional dynamic arrays and I've scowered StackOverflow and C++ tutorial sites trying to find a fix to my problem, but I can't seem to find any. Anyways I am trying to initialize a 2D dynamic array with values obtained from a text file and I'm experiencing some errors and problems. The numbers are meant to be placed inside the array to form a matrix. But every time I run my code it gives me an "Application.exe has stopped working error".
bool loadMatrix(const char *filename, int **matrix, int& rowCount, int& columnCount);
*matrix = new int[ rowCount * columnCount];
for( size_t currentRow=0; currentRow<rowCount; currentRow++) {
for( size_t currentColumn=0; currentColumn<columnCount; currentColumn++){
//This takes the value from the vector lines<> to be stored in the matrix
int value = stoi(lines[currentRow][currentColumn], 0, 10);
*matrix[currentRow * columnCount + currentColumn] = value;
}
}
it is 100% something to do with the last line in the code above, as all the rest of the code had been given in the assignment skeleton. I have edited and changed the code in every way to try and fix the error. One attempt fixed it, but caused another bug with all elements of the array being overwritten by the last element, as seen below:
matrix[currentRow * columnCount + currentColumn] = &value;
But as you can see, this causes another problem, as now all the values in the matrix are overwritten by the last. As well, the array needs to be updated such that what values are added are accessible outside this function, and the above code won't allow the updated matrix to accessed outside of this function. Below is the output error of the above line of code:
1, 2, 3
4, 5, 6
results as
6, 6, 6
6, 6, 6
I'm not too sure why the first attempt causes this error, but I understand the second attempt is due to some pointer to memory error.
Any ideas on how I could fix this?
Thanks in advance
This might be too basic, but I would like to ask. I have my code in Java that copies the start array to newStart and assigns the last element to another array.
int[] newStart= Arrays.copyOf(start, start.length + 1);
newStart[start.length] = array[i];
I converted it to my C++ version with vectors as:
vector<int> newStart(5); //Doesnt have to be 5, sth not known
newStart.insert(newStart.end(), start.begin(), start.end());
newStart[start.size()] = array[i];
However, my code doesn't do what I require. That adds the vector one to the other's end, and makes new assignments accordingly. What is the right way to do that?
C++ vectors don't auto-resize on element access (through operator[] nor at method). Replace the last line with either
newStart.push_back(array[i]);
or
newStart.resize(start.size() + 1);
newStart[start.size()] = array[i];
(the former being more efficient, because it does not default-initialize the element first)
I believe Java arrays don't auto-resize either, so I wouldn't expect the Java code to work either (but it will give exception while the C++ code will make daemons fly out of your nose or whatever else nasty the compiler will think of).
Edit: Reading the question again, the code there is actually defined, but the more wrong.
vector<int> newStart(5); //Doesnt have to be 5, sth not known
This statement actually creates a vector that contains 5 (or whatever) default initialized elements, which in case of int is 0. So now you have
{0, 0, 0, 0, 0}
For sake of example let's say start contains {1, 2, 3, 4, 5, 6, 7}.
newStart.insert(newStart.end(), start.begin(), start.end());
vector::insert adds new elements extending the array and moving the following elements as necessary. The insert is before end, so it will append to the vector, resulting in:
{0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7}
I don't think this is what you wanted. It looks like you wanted a copy of start. Which you'd simply create by copy constructing: vector<int> newStart(start).
newStart[start.size()] = array[i];
Now newStart has the initial 5 zeroes and the elements from start, so it's size is start.size() + 5 and therefore it does have index start.size(). It is the 5th element from end. So per above example, this will modify the vector to:
{0, 0, 0, 0, 0, 1, 2, 1, 4, 5, 6, 7}
^
To append start[0] to the end, use push_back as per above.
Also remember, that Java arrays are reference types, where assignment just shares reference to the same array, but C++ vectors are value types where the content is copied on assignment.
I'm a little confused by the mixing of Java and C++. Hopefully one of the explinations below will help.
If you're in C++, vector has an overloaded operator= so you can just type
newvector = oldvector;
and it will copy.
If you're in java, you can use the copy constructor ex:
Vector v2 = new Vector(v1);
Try this:
for (std::vector<int>::iterator it = start.begin() ; it != start.end(); ++it) {
newStart.push_back (*it);
}
Use std::copy algorithm and back_inserter iterator.
Sample code:
#include <iterator>
#include <vector>
#include <algorithm>
int main () {
std::vector<int> src;
std::vector<int> dest;
std::copy(src.begin(),src.end(),back_inserter(dest));
}
I am currently browsing over some old college snippets of c++ code. Back then, one of the other class was assigned with doing a matrix class using double pointers and 2D arrays. Luckily (or unluckily upon hindsight) I never did get a chance to learn stuff like that. I borrowed their code when we graduated for future review. If anyone can please explain to me what exactly happens in this snippet:
//This is a constructor of a 1x1 matrix
signal::signal(){
_nrows = 1;
_ncols = 1;
_coef = new double*[_nrows];
_coef[0] = new double[_ncols];
_coef[0][0] = 0.0;
}
Just a sidenote, _coef is a ** of type double.
From what I understand, _nrows and _ncols are given a value of 1 (meaning their sizes). Then, the code dynamically creates a double* out in the heap with elements equal to _nrows; the problem is, I dont exactly know what happens next. Why is the array corresponding to _ncols not a pointer? Why is it assigned _coef[0]?
In memory, a two dimensional array (n, m) looks more or less like this
_coef -> | _coef[0] -> {1, 2, 3, ..., m}
| _coef[1] -> {1, 2, 3, ..., m}
| _coef[2] -> {1, 2, 3, ..., m}
| ...
| _coef[n] -> {1, 2, 3, ..., m}
_coef points to an array of n pointers. And each of these pointers point to an array of m doubles.
So, in your case _coef points to an array of 1 pointer and this pointer points to an array of one double.
Now to your questions
It is not a pointer, because in your second dimension, you finally want to store the doubles, not pointers.
It is assigned to _coef[0], because it is the first, and only, row of your two dimensional array.
The first two lines, as you say, assign the value 1 to each of _nrows and _ncols.
The following line dynamically allocates an array of double* (pointers to double). The number of double* objects allocated is _nrows (which is 1 in your case). Think of that syntax as similar to defining a normal automatic array, double* array[1], where the number of elements is 1. Then _coef is a pointer to the first of those double pointers. I'll represent the memory representation diagrammatically:
_nrows = 1
_ncols = 1
_coef ---> _coef[0] ---> Currently points nowhere in particular
So now you have _nrows amount of double* lined up in memory. _coef[0] refers to the first of those double*. A new dynamically allocated array, this time of doubles, is created of size _ncols. A pointer to the first of those doubles is assigned to _coef[0]. That is, the first double* in the first dynamically allocated array now points to the first double in the second dynamically allocated array.
_nrows = 1
_ncols = 1
_coef ---> _coef[0] ---> _coef[0][0]
Then _coef[0][0] = 0.0 sets the first double in the second dynamically allocated array to 0. Since it's the only double, because the sizes of both of your dynamically allocated arrays are 1, you have initialized all doubles to 0.
_nrows = 1
_ncols = 1
_coef ---> _coef[0] ---> _coef[0][0] = 0