After some experiments I've come up with these four ways of creating multidimensional array on the heap (1 and 2 is kinda the same except that the result for 1 I wanted reference):
#include <memory>
#include <iostream>
template <typename T>
void printArr(T const &arr)
{
std::cout << typeid(T).name() << "\t";
for (int x = 0; x < 2; ++x)
for (int y = 0; y < 2; ++y)
for (int z = 0; z < 2; ++z)
std::cout << arr[x][y][z] << " ";
std::cout << std::endl;
}
int main()
{
int(&arr)[2][2][2] = reinterpret_cast<int(&)[2][2][2]>(*new int[2][2][2]{ { { 1,2 },{ 3,4 } }, { { 5,6 },{ 7,8 } } });
printArr(arr);
delete[] &arr;
int(*arr2)[2][2] = new int[2][2][2]{ { { 1,2 },{ 3,4 } },{ { 5,6 },{ 7,8 } } };
printArr(arr2);
delete[] arr2;
std::unique_ptr<int[][2][2]> arr3(new int[2][2][2]{ { { 1,2 },{ 3,4 } },{ { 5,6 },{ 7,8 } } });
printArr(arr3);
std::unique_ptr<int[][2][2]> arr4 = std::make_unique<int[][2][2]>(2);
printArr(arr4);
return 0;
}
Tested this on various online compilers without problems, so what I would like to know if they are valid ways as well?
Here is the demo https://ideone.com/UWXOoW and output:
int [2][2][2] 1 2 3 4 5 6 7 8
int (*)[2][2] 1 2 3 4 5 6 7 8
class std::unique_ptr<int [0][2][2],struct std::default_delete<int [0][2][2]> > 1 2 3 4 5 6 7 8
class std::unique_ptr<int [0][2][2],struct std::default_delete<int [0][2][2]> > 0 0 0 0 0 0 0 0
I think your first example is undefined behavior or at least would lead to undefined behavior as soon as you'd try to actually access the array through the reference arr.
new int[2][2][2] creates an array of two int[2][2]. It returns you a pointer to the first element of this array ([expr.new] ยง1). However, a pointer to the first element of an array and a pointer to the array itself are not pointer interconvertible. I'm not sure if there is a definitive answer yet to the philosophical question "does the act of dereferencing an invalid pointer itself already constitute undefined behavior?". But at least accessing the reference obtained from your reinterpret_cast should definitely violate the strict aliasing rule. The other three should be fine.
Edit:
As there still seems to be some confusion, here a more detailed explanation of my argument:
new int[2][2][2]
creates an array of two int[2][2] and returns a pointer to the first element of this array, i.e., a pointer to the first int[2][2] subobject within this array and not the complete array object itself.
If you want to get an int(*)[2][2][2] from new, you could, e.g., do
new int[1][2][2][2]
Related
This question already has answers here:
Initialization of all elements of an array to one default value in C++?
(12 answers)
Closed 3 months ago.
I'm trying to initialize a single value to whole array in c++.
For ex:- I want to initialize 1 in whole array by writing it by only once
I have tried to initializing 1 in whole array but it throws error , I'm expecting 1 in whole array.
ex- int array[5]={0};
output- 0 0 0 0 0
int array[5]={1};
output- 1 0 0 0 0
expecting- 1 1 1 1 1
if you want 1 value at very index you can do this by
int arr[5] = {1,1,1,1,1}; or
int arr[5];
arr[0] = 1;
arr[1] = 1;
arr[2] = 1;
arr[3] = 1;
arr[4] = 1;
otherwise if you write arr[5] = {1}; only first index will have value 1 rest will be assigned zero automatically like this {1,0,0,0,0}
or #include <iostream>
using namespace std;
int main()
{
int arr[5];
memset(arr, 1, sizeof(arr));
cout << arr;
return 0;
}
so type this code this memset function will fill all the index with value 1 by writing it only once.
hope this answer helps you.
Edited, try this code snippet working perfectly fine
#include <iostream>
#include <array>
int main () {
std::array<int,5> myarray;
myarray.fill(1);
std::cout << "myarray contains:";
for ( int& x : myarray) { std::cout << ' ' << x; }
std::cout << '\n';
return 0;
}
int* snap = nullptr;
int last = -1;
void func(int* md){
if(snap!=nullptr) {
last = *snap;
}
snap = md;
cout<<last<< " "<<*snap<<endl;
}
int main() {
for(int i =0;i<10;i++) {
int arg = i;
func(&arg);
}
return 0;
}`
Output
-1 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
Shouldn't the 'last' variable have the previous iteration's value of 'snap'. But the values are equal. What am I doing wrong here?
On the second iteration of your for loop, snap points to a dangling pointer. The int arg that it points to has fallen out of scope.
While it is a dangling pointer, you dereference it, causing undefined behavior.
In my main() function I have declared an array of type int with the numbers 1 to 10. I then have two other functions of type int* that take this array and its size as parameters, perform some operations, and each returns a pointer to the new array. Where I'm having issues is with a third function that prints the contents of the array.
#include <iostream>
using namespace std;
const int SIZE_OF_ARRAY = 10;
int main() {
int array[SIZE_OF_ARRAY] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int *ptr1 = 0;
ptr1 = function1(array, SIZE_OF_ARRAY);
print(array, SIZE_OF_ARRAY);
cout << endl;
int *ptr2 = 0;
ptr2 = function2(array, SIZE_OF_ARRAY);
print(array, SIZE_OF_ARRAY);
return 0;
}
void print(int array[], const int SIZE_OF_ARRAY)
{
for (int i = 0; i < (SIZE_OF_ARRAY * 2); i++)
{
cout << array[i] << " ";
}
}
int* function1(int array[], const int SIZE_OF_ARRAY)
{
int *ptr = new int[SIZE_OF_ARRAY];
// Do stuff.
return ptr;
}
int* function2(int array[], const int SIZE_OF_ARRAY)
{
int *ptr2 = new int[SIZE_OF_ARRAY * 2];
// Create new array double in size, and set contents of ptr2
// to the contents of array. Then initialize the rest to 0.
return ptr2;
}
As expected here, the result of calling the print() function twice is something like:
1 2 3 4 5 6 7 8 9 10 465738691 -989855001 1483324368 32767 -1944382035 32767 0 0 1 0
1 2 3 4 5 6 7 8 9 10 465738691 -989855001 1483324368 32767 -1944382035 32767 0 0 1 0
But I want the result to be like this instead:
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10 0 0 0 0 0 0 0 0 0 0
How can I accomplish this? (Note that for this assignment I'm using C++98). Thanks in advance.
new int[SIZE_OF_ARRAY] allocates memory, but doesn't assign values to the array elements. What you are seeing is what was in that memory when it got allocated for the array. You can change your function2 to assign zeroes to array elements, if that's what you want.
First of all, you want to print different number of elements on the two calls to print, so you should not delegate deciding whether to multiply the size by two to the print, but rather do it on the calling side. Change the print function to only iterate up to SIZE_OF_ARRAY, and change the two places where you call it to:
print(ptr1, SIZE_OF_ARRAY);
and
print(ptr2, SIZE_OF_ARRAY * 2);
correspondingly.
Now, I assume that your second function does assign values to all 20 elements, but if it does not, the ones to which it did not assign values would continue containing garbage. To get around it, just initialize them at the beginning of the second function:
int *ptr2 = new int[SIZE_OF_ARRAY * 2];
for (size_t i = 0; i < SIZE_OF_ARRAY * 2; ++ i) ptr2[i] = 0;
With these two changes you should get the desired behavior.
Also, if you allocate something with new[], you need to delete it with delete[], otherwise you get a memory leak. Add these two lines at the end of main:
delete[] ptr1;
delete[] ptr2;
Note, that using delete instead of delete[] would be wrong in this case. If something is allocated as an array, it must be deleted as an array.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C and C++ : Partial initialization of automatic structure
While reading Code Complete, I came across an C++ array initialization example:
float studentGrades[ MAX_STUDENTS ] = { 0.0 };
I did not know C++ could initialize the entire array, so I've tested it:
#include <iostream>
using namespace std;
int main() {
const int MAX_STUDENTS=4;
float studentGrades[ MAX_STUDENTS ] = { 0.0 };
for (int i=0; i<MAX_STUDENTS; i++) {
cout << i << " " << studentGrades[i] << '\n';
}
return 0;
}
The program gave the expected results:
0 0
1 0
2 0
3 0
But changing the initialization value from 0.0 to, say, 9.9:
float studentGrades[ MAX_STUDENTS ] = { 9.9 };
Gave the interesting result:
0 9.9
1 0
2 0
3 0
Does the initialization declaration set only the first element in the array?
You only initialize the first N positions to the values in braces and all others are initialized to 0. In this case, N is the number of arguments you passed to the initialization list, i.e.,
float arr1[10] = { }; // all elements are 0
float arr2[10] = { 0 }; // all elements are 0
float arr3[10] = { 1 }; // first element is 1, all others are 0
float arr4[10] = { 1, 2 }; // first element is 1, second is 2, all others are 0
No, it sets all members/elements that haven't been explicitly set to their default-initialisation value, which is zero for numeric types.
I've been pretty confused while programming before, but this one takes the cake. Basically I set the value in one for loop, and in the following iteration it changes to the value of the next one.
for (int i = 0; i < 2; ++i)
{
for (int j = 0; j < numWords[i]; ++j) //numWords [0] = 9, numWords [1] = 7
{
stb[i][j].word = const_cast<char*>(is (j + 1,1).c_str()); //is(int,length[opt]) converts int to string, c_str() returns const char *, but I need char *
cout << is(j+1,1) << ' ' << stb[i][j].word << '\n';
}
}
for (int i = 0; i < 2; ++i)
{
for (int j = 0; j < numWords [i]; ++j)
{
cout << stb[i][j].word << ' ';
}
cout << '\n';
}
Output:
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
1 1
2 2
3 3
4 4
5 5
6 6
7 7
7 7 7 7 7 7 7 7 7
7 7 7 7 7 7 7
My only guess now is something with the const, but it doesn't make sense why it would keep changing all previous array elements...
This is pretty simple. Your program has undefined behaviour (if my assumptions about is() are correct).
is(int, length) returns a std::string by value. You get a pointer to some internal structure in that string by using c_str(). This string is then destructed at the end of the full-expression. This destruction invalidates the pointers that you obtained from c_str().
This means that you fill up the array with pointers to invalid memory. You then read from these pointers to print out the contents of the array. Reading from invalid memory results in undefined behaviour.
A possible explanation for the observed behaviour is this:
Each string that is returns reuses the same memory. In the first loop you read from the memory before it has been overwritten by another call to is, and so you get the correct value. In the second loop you read from the memory after it has been overritten, and so you get the final value in the array.