I've been studying C++ for a test and I am currently stuck with pointer arithmetic.
The basic problem is the following:
int numColumns = 3;
int numRows = 4;
int a[numRows][numColumns];
a[0][0] = 1;
a[0][1] = 2;
a[0][2] = 3;
a[1][0] = 4;
a[1][1] = 5;
a[1][2] = 6;
a[2][0] = 7;
a[2][1] = 8;
a[2][2] = 9;
a[3][0] = 10;
a[3][1] = 11;
a[3][2] = 12;
for (int i=numColumns-1; i>-1;i--)
{
cout << a[numRows-1][i] << endl;
}
A very simple program which prints the lower "row of the matrix". i.e. 12,11,10.
Now I am trying to do the equivalent with a int*.
What I have been told by my classmates is to think it like this:
array[i][j] == p[numColumns*i+j]
If that is correct, shouldn't the following be equivalent to what I'm looking for:
int* p = reinterpret_cast<int*> a;
for (int i=numColumns-1; i>-1;i--)
{
cout << p[numColumns*(numRows-1)+i] << endl;
}
Thanks.
int array[3][5] is NOT an abstraction (in the C++ language) for int array[3*5]. The standard says that a 2 dimensional array (and N-dimensional arrays in general) are arrays of arrays. That array[3][5] is an array of three elements, where each element is an array containing 5 elements (integers in this case). C++'s type system does make that distinction.
According to the C++ standard, and array T array[N] is a contiguous block of memory containing the N elements of type T. So that means that a multidimensional array, let's say int array[3][5] will be a continuous block of memory containing 3 int[5] arrays, and each int[5] array is a contiguous block of 5 ints.
On my machine, the memory ends up laid out exactly as you would expect - identical to int array[3*5]. The way the memory is treated is different however, due to the type system (which distinguishes between int[] and int[][]). This is why you need to use a reinterpret_cast which essentially tells your compiler "take this memory and without doing any conversion, treat it like this new type".
I'm not completely sure if this memory layout is guaranteed however. I couldn't find anything in the standard stating that arrays can't be padded. If they can be padded (again, I'm not sure) then it's possible that the int[5] array is not actually 5 elements long (a better example would be char[5], which I could see being padded to 8 bytes).
Also there is an appreciable difference between int* and int** since the latter doesn't guarantee contiguous memory.
EDIT: The reason that C++ distinguishes between int[3*5] and int[3][5] is because it wants to guarantee the order of the elements in memory. In C++ int[0][1] and int[0][2] are sizeof(int) apart in memory. However in Fortran, for example, int[0][0] and int[1][0] are sizeof(int) apart in memory because Fortran uses column major representation.
Here's a diagram to help explain:
0 1 2
3 4 5
6 7 8
Can be made into an array that looks like {0,1,2,3,4,5,6,7,8} or an array that looks like: {0,3,6,1,4,7,2,5,8}.
Hint: in your original code, the type of a is more similar to int**, so you shouldn't cast it to int*. It is a pointer to pointer to something.
If you want to access it like an 1-D array, then a has to be defined as an 1-D array as well.
#rwong: Really? I thought that multi-dimensionals arrays were just an "abstraction" for us, since the following are equivalent:
int array[3][5];
int array[3*5];
Anyways, I detemined what was wrong. As usual it was not my code, but copy-pasting someone's code and working from there.
What I had was this:
for(int i=numRows-1; i>-1 ;i++)
{
cout << p[numColumns*numRows-1+i] << endl;
}
Is funny because I did not copy-paste my code from VS, but actually wrote it from scratch to "illustrate" my error.
Lesson to be learnt here ;)
Edit: I'm still not sure about what rwong explained here. Would anyone care to elaborate?
Another way to think about it: since a is similar to an int**, is there a part of a that's similar to an int*?
Related
I am trying to learn C++, I have a fair bit of experience in C# and the 2 languages are so dissimilar and I am having trouble understanding data types and pointer variants of data types and the initialization of them, please consider the code below:
wchar_t *array = new wchar_t[10]; //Declaring a pointer of wchart_t and initializing to a wchar_t array of size 10 ?
auto memAddressOfPointer = &array; //auto is resolving memAddressOfPointer to a pointer of a pointer?
cout << array << endl; //Printing the memory address of array not the object created above?
cout << *array << endl; //Getting the actual value of the object (empty wchar_t array of size 10 in bytes?
cout << &array << endl; //Printing the address of the obj?
cout << memAddressOfPointer << endl; //Printing the address of the obj ?
My question is why would I create a pointer and initialize it? Why not just create an array of wchar_t? like:
wchar_t array [10];
I refer to this stack post as well:
Unable to create an array of wchar_t
Thank you for your consideration.
If you know the size of the number of elements you need to put in the array, then just use the array i.e., wchar_t arr[10];.
If you don't know the size, you can create the array at runtime using dynamic memory allocation with the required size i.e., wchar_t *arr = new wchar_t[required_size]. Once the memory is allocated, you need to deallocate it using delete[] operator for arrays and delete for non-array pointers. However I highly recommend you don't do that and instead either
Use std::wstring in this particular case which will automatically handle this for you.
Use std::vector for everything else if you can. It's a dynamic array which will grow automatically. No manual memory management etc.
In case you have to use pointers, use a smart pointer like unique_ptr or shared_ptr. The advantage of using smart pointers is that they will automatically clean up once they go out of scope.
If you know the extent of the array when writing the program, there's absolutely nothing wrong with wchar_t array [10];. If 10 is a fixed (constexpr) number - stick with that.
What wchar_t *array = new wchar_t[10]; lets you do is to let 10 be a number that you find out in run-time. You can change 10 to x and let x be a number that the user supplies or that you calculate somehow. wchar_t array [x]; when x is not a constexpr is on the other hand not valid C++ (but is available as an exension, called VLA, in some implementations).
Note: One downside with using new is that you need to make sure you delete the same pointer. This is not always simple. Using these raw pointers is therefore not what you usually want to do. Instead, use a smart pointer, like std::unique_ptr<wchar_t[]>, and the resource will be delete[]d when the pointer goes out of scope.
The advantages of creating a pointer instead of an array are the dynamic allocation that you can take advantage of and also the properties of the pointer that might help.
Consider the following code that represent the dynamic allocation and reallocation:
int x;
cin >> x;
int *oldArr = malloc(x * sizeof(int));
for(int i = 0; i < x; i++)
arr[i] = i;
cin >> x;
arr = realloc(arr, x * sizeof(int));
Here is another example that shows one of the pointer features which also you can use along with arrays.
int arr[5] = {1, 2, 3, 4 ,5};
int *ptr = arr;
cout << *ptr;
ptr++;
cout << *ptr;
cout << *(ptr + 1);
Despite these advantages and others, I think that the example you are presenting of using pointers instead of arrays is just for academic purposes to understand how to work with pointers in order to build more complex data structures using pointers in future lessons as you are using constant size arrays.
This question already has answers here:
What is array to pointer decay?
(11 answers)
Closed 4 years ago.
So I've been searching on Stackoverflow for all the code that can find the size of a pointer to an array. I couldn't find it.
int main() {
int array[] = {6,3, 4, 6, 2};
int *sizes = array;
cout << sizeof(sizes); // output is 8
}
Using sizeof doesn't work. Can anyone suggest a good solution? Thanks a lot!
**EDIT:
I want to find the size of the array using the pointer "sizes". I know how to find the size using the "array" variable
You can read in c++ doc http://www.cplusplus.com/reference/array/array/size/
For example:
// array::size
#include <iostream>
#include <array>
int main ()
{
std::array<int,5> myints;
std::cout << "size of myints: " << myints.size() << std::endl;
std::cout << "sizeof(myints): " << sizeof(myints) << std::endl;
return 0;
}
If you want C level answer, why did you tag this question as c++?
int main() {
int array[] = {6,3, 4, 6, 2};
cout << sizeof(array) / sizeof(int);
return 0;
}
It might not be satisfy but it's impossible to find the array's size using a pointer to the array. Pointer unlike the array, can point to any type of variable with the right casting. It doesn't store a straight memory allocation places like the array. That's why you'll always get 8 bytes in 64bit OS architecture or 4 bytes in 32bit OS architecture of size when you do sizeof(pointer).
Read about the differences between pointers and arrays in c.
Within the scope that array was declared in, sizeof(array) is the number of bytes in the array.¹
If you want the number of elements in array, that’s (sizeof(array)/sizeof(array[0])).
Since sizes is declared as an int*, sizeof(sizes) is the size of a pointer. That will be 8 for a 64-bit program, 4 for a 32-bit program, or some other size on an unusual architecture.
There is one other wrinkle: if you pass array to a function, such as:
int* reverse_array( int a[], const size_t n )
{
assert( sizeof(a) == sizeof(int*) );
// ...
}
Then the array parameter, a, automatically degrades to a pointer, and the compiler forgets its actual size. This is for backward-compatibility with C.
To use an array within another function, you must pass the size as a separate parameter, in this case n, or use a type such as std::array<int>, std::vector<int>, or a struct. The latter is what Bjarne Stroustrup’s C++ guidelines recommend, although, if you use a STL template in the ABI of a library, you are introducing a dependency on a particular implementation of the STL.
¹ Since this community loves language-lawyering: some historical C compilers measured sizes in increments other than bytes. Some C++ compiler hypothetically might make char more than 8 bits wide (although not less!) and claim to be technically conforming to the standard. You don’t need to worry about that possibility right now. Seriously, you don’t.
I am working on a program in c++ in which the user can add phone numbers to a list. For this assignment, we have to use pointers while dynamically allocating the memory needed. The code below works fine, except for the fact that when the program lists the elements in the pointer, random numbers are spit out. I'm new to c++ so any ways I could be pointed into the right direction of fixing this issue are greatly appreciated.
int *FirstArray = new int(size);
int *SecondArray = new int(size + 1);
if (size == 0) {
cout << "Please enter the number which you would like to add";
cin >> FirstArray[size];
for (int x = 0; x <= size; x++) {
cout << x << ". " << FirstArray[x] << endl;
}
for (int x = 0; x <= size; x++) {
FirstArray[x] = SecondArray[x];
}
SecondArray = FirstArray;
delete (FirstArray);
}
else {
cout << "Please enter the number which you would like to add";
cin >> SecondArray[size];
for (int x = 0; x <= size; x++) {
cout << x + 1 << ". " << SecondArray[x] << endl;
}
}
size++;
Apart from the fact that a std::vector would be really the better choice for such application I think learning about pointers is a good starting point to understand why the usage of std-containers is better.
The whole if(size==0)-block in your code snippet is unsafe as well as the else-scope in further consequence because FirstArray[x] reads from memory which is not allocated at least for every x > 0.
So called segmentation faults are then very likely in such cases though such may be defered in case of debugger friendly memory layout or other reasons.
Besides the fact that you then never had really a list but just two values refered by two single-element arrays (or just pointers) it's then clear why you get only random numbers from the memory pointed to by the pointers.
A pointer in C (or C++) is not restricting the access to succeeding elements behind the first element.
This means, that pointers can be used for either single values (which is exactly the same as an array with size == 1) and arrays with more than one element.
Some more issues...
Use new int[] rather than new int() because in this context curved brackets () is understood as argument list to the compiler generated 'constructor' of the data type 'int' which in case of int() just sets the value. C++ is consequently applying its type paradigms to primitive types as well and not only classes. See another SO article on this topic
Using new int[size] instead does what you want. It allocates memory for an integer array with 'size' elements and returns the pointer to the first element.
I think you do not need a SecondArray. A statement like "SecondArray = FirstArray" is anyway not copying the elements. It's copying the pointers and leaving the memory allocated to SecondArray behind as a memory leak.
Deleting then FirstArray with "delete (FirstArray)" makes it even worse because then you delete FirstArray and SecondArray at once because both point to the same memory location and any further access to SecondArray would be dangerous (segfault etc.)
Incrementing size++ at the end is as well in vain (if I got your idea right) because the size should be clear before you allocate and access the memory, not afterwards.
Resizing the array in case that 'size' changes can be done either by calling new(FirstArray)[size] (which is seldomly used directly but common in std-containers) or by consequently giving up using C++ and switching to the ANSI C style with malloc() for initial allocation, realloc() for resizing, memcpy() for copying/assignment and finally free() for deallocation. But switching to ANSI C style in this case doesn't mean that you are not allowed to use it in a C++ context. BTW, in most standard C++ frameworks the new-operator and the delete-operator call malloc() and free() behind the scenes.
At the end of the day, using std::vector<> can make life MUCH easier ;-)
This question already has answers here:
Why can't we use double pointer to represent two dimensional arrays?
(6 answers)
Closed 6 years ago.
int main()
{
matrix[2][4] = {{11,22,33,99},{44,55,66,110}};
int **ptr = (int**)matrix;
printf("%d%d",**matrix,*ptr);
}
But when a 2-d array is passed as a parameter it is typecasted into (*matrix)[2] ..
what type does the compiler store this array as... is it storing as a 2-d array or a double pointer or an pointer to an array .. If it is storing as an array how does it interprets differently at different situations like above. Please help me understand.
Is 2d array a double pointer?
No. This line of your program is incorrect:
int **ptr = (int**)matrix;
This answer deals with the same topic
If you want concrete image how multidimensional arrays are implemented:
The rules for multidimensional arrays are not different from those for ordinary arrays, just substitute the "inner" array type as element type. The array items are stored in memory directly after each other:
matrix: 11 22 33 99 44 55 66 110
----------- the first element of matrix
------------ the second element of matrix
Therefore, to address element matrix[x][y], you take the base address of matrix + x*4 + y (4 is the inner array size).
When arrays are passed to functions, they decay to pointers to their first element. As you noticed, this would be int (*)[4]. The 4 in the type would then tell the compiler the size of the inner type, which is why it works. When doing pointer arithmetic on a similar pointer, the compiler adds multiples of the element size, so for matrix_ptr[x][y], you get matrix_ptr + x*4 + y, which is exactly the same as above.
The cast ptr=(int**)matrix is therefore incorrect. For once, *ptr would mean a pointer value stored at address of matrix, but there isn't any. Secondly, There isn't a pointer to matrix[1] anywhere in the memory of the program.
Note: the calculations in this post assume sizeof(int)==1, to avoid unnecessary complexity.
No. A multidimensional array is a single block of memory. The size of the block is the product of the dimensions multiplied by the size of the type of the elements, and indexing in each pair of brackets offsets into the array by the product of the dimensions for the remaining dimensions. So..
int arr[5][3][2];
is an array that holds 30 ints. arr[0][0][0] gives the first, arr[1][0][0] gives the seventh (offsets by 3 * 2). arr[0][1][0] gives the third (offsets by 2).
The pointers the array decays to will depend on the level; arr decays to a pointer to a 3x2 int array, arr[0] decays to a pointer to a 2 element int array, and arr[0][0] decays to a pointer to int.
However, you can also have an array of pointers, and treat it as a multidimensional array -- but it requires some extra setup, because you have to set each pointer to its array. Additionally, you lose the information about the sizes of the arrays within the array (sizeof would give the size of the pointer). On the other hand, you gain the ability to have differently sized sub-arrays and to change where the pointers point, which is useful if they need to be resized or rearranged. An array of pointers like this can be indexed like a multidimensional array, even though it's allocated and arranged differently and sizeof won't always behave the same way with it. A statically allocated example of this setup would be:
int *arr[3];
int aa[2] = { 10, 11 },
ab[2] = { 12, 13 },
ac[2] = { 14, 15 };
arr[0] = aa;
arr[1] = ab;
arr[2] = ac;
After the above, arr[1][0] is 12. But instead of giving the int found at 1 * 2 * sizeof(int) bytes past the start address of the array arr, it gives the int found at 0 * sizeof(int) bytes past the address pointed to by arr[1]. Also, sizeof(arr[0]) is equivalent to sizeof(int *) instead of sizeof(int) * 2.
In C, there's nothing special you need to know to understand multi-dimensional arrays. They work exactly the same way as if they were never specifically mentioned. All you need to know is that you can create an array of any type, including an array.
So when you see:
int matrix[2][4];
Just think, "matrix is an array of 2 things -- those things are arrays of 4 integers". All the normal rules for arrays apply. For example, matrix can easily decay into a pointer to its first member, just like any other array, which in this case is an array of four integers. (Which can, of course, itself decay.)
If you can use the stack for that data (small volume) then you usually define the matrix:
int matrix[X][Y]
When you want to allocate it in the heap (large volume), the you usually define a:
int** matrix = NULL;
and then allocate the two dimensions with malloc/calloc.
You can treat the 2d array as int** but that is not a good practice since it makes the code less readable. Other then that
**matrix == matrix[0][0] is true
I started learning C++ and I wanted to implement a simple 2D array and get its size without using std::vector. However I run into weird errors with my second dimension:
int **data= new int*[2];
for (int i = 0; i<2;i++){
data[i] = new int[3];
}
data[0][0] = 1;
data[0][1] = 2;
data[0][2] = 3;
data[1][0] = 4;
data[1][1] = 5;
data[1][2] = 6;
data[1][25] = 20; //Should segfault? AAAAA
cout << "Data[1][25] = " << data[1][25] << endl; //Should segfault, no?
int n = sizeof(data[0]) / sizeof(int);
int m = sizeof(data) / sizeof(int);
cout << "M is " << m << " N is " << n << endl;// Reports m = 2, n =2?!?!? BBBB
At AAAA I should be getting segfault, no? Instead I am able to assign a value and later read it. The value of data[1][any] is zero, like it has been initialized. This is only a problem in the second dimension, the first dimension behaves as expected.
Later at BBBB I am not getting an accurate size for n. Am I doing something wrong?
C++ does not do bound checking on arrays. Accessing data outside the bounds of an array is undefined behavior and anything can happen. It may cause a segfault it might not. If you have valid memory regions before or after the array you can end up accessing or modifying that memory instead. This can lead to corruption of other data used by your program.
Also you use of sizeof is incorrect. sizeof is a compile time construct. It cannot be used to determine the size of an array through a pointer value at runtime. If you need that type of functionality use std::array or std::vector.
char somearray[10];
int size = sizeof(somearray); // result is 10. Yay it works.
char *somearrayptr = new char[10];
int size = sizeof(somearrayptr); // size = the size of char* not char[10].
At AAAA you have undefined behavior. Just anything can happen from that point on -- and more interesting, even before.
In standard C++ there is no such behavior as 'segfault'. And implementation could define some operations to do that but I'm not aware if any ever bothered. It just happens by chance for some cases.
Accessing an array outside its boundaries is undefined behavior. So there is no reason to expect anything in particular will happen: it could crash, return the right answer, return the wrong answer, silently corrupt data in another part of the program, or a whole host of other possibilities.
data[1][25] = 20; //Should segfault? AAAAA
It would segfault if you are not allowed to access the location. There is no checking in C++ to see if the location you are accessing is valid frrm the code-point of view.
You obtained an output because that was stored at that location. It could have been anything. This is undefined behaviour and you may not get the same result everytime.
See this answer, though it talks abput local variables , but it gives nice examples about how such accessing of data can be undefined behaviour
data and data[0] are both pointers (doesn't matter single or double). They have a defined size for every implementation. In your case, size of pointer is twice that of size of int on your machine. Hence, the output. sizeof when used with pointers pointing to arrays (and not arrays i.e. ones declared as arrays char a[] etc) gives the size of the pointer
Both data[0] and data are pointers. Pointers will be size 4 on a 32-bit system, and 8 on a 64-bit system. Therefore, m and n are equal. Size of int is always 4.