pointer to pointer to and pointer to arrays - c++

could someone give me a brief explanation of what is happening differently in the functions below?
void f1(data_t **d)
{
for (int i=0; i<MAXSIZE; i++)
{
(*d)[i].ival = i;
}
}
void f2(data_t **d)
{
for (int i=0; i<MAXSIZE; i++)
{
(*d)->ival = i;
(*d)++
}
}
void f3(data_t *d)
{
for (int i = 0; i<MAXSIZE; i++)
{
d->ival = i;
d++;
}
}
void f4(data_t *d)
{
for (int i = 0; i<MAXSIZE; i++)
{
d[i].ival = i;
}
}
particularly what is happening differently in f2. but clearly different things are happening in each.
f1 and f3 do the same thing (but differently). f2 fails completely, and f4 is buggy (works in this example, but when i tried to put other values into other pointers (char *) the strings end up strange.)

void f1(data_t **d)
{
for (int i=0; i<MAXSIZE; i++)
{
(*d)[i].ival = i;
}
}
The d seems to be a pointer to array of data_t's (or is a 1-element array of arrays of data_t). It is dereferenced to recover the array of data_t's and then i-th element of this array is modified.
void f2(data_t **d)
{
for (int i=0; i<MAXSIZE; i++)
{
(*d)->ival = i;
(*d)++
}
}
This is a bit tricky and indeed does something different than in the first case. There was a pointer to array of data_t's. Here we have an array of pointers to data_t's. The pointer to first element is dereferenced to retrieve a pointer to data. Then -> is used to access the data and value is modified ( x->y = (*x).y ). Finally the pointer is moved to the next element of main array.
void f3(data_t *d)
{
for (int i = 0; i<MAXSIZE; i++)
{
d->ival = i;
d++;
}
}
Here we have simpler case, the d is just an array of data_t's accessed by pointer. Inside the loop, an element is accessed by ->, and then d is incremented to point to next element of array.
void f4(data_t *d)
{
for (int i = 0; i<MAXSIZE; i++)
{
d[i].ival = i;
}
}
Similarly to f3, elements are modified by the [] operator.
Note the following facts:
int[] =(def) int *
if a is of type int * and i is of any integral type, then:
*(a + i) =(def) a[i]
Also, if a points to first element of an array, then
*a =(def) a[0]
and then, after a "a++"
*a =(def) a[1]
...and so on.

Let's take these one at a time:
// f1
(*d)[i].ival = i;
First, (*d) is dereferencing d, which appears to be a pointer to an array of data_t variables. This allows access to the actual array, such that [i] is accessing the i-th element of the array and assigning i to it.
// f2
(*d)->ival = i;
(*d)++;
(*d) is dereferencing d just like in the first one. However, there is one crucial bit of information about arrays that you should understand before moving on...
int j[2] = { 42, 50 };
int j0 = *j; // j0 is now 42
j += 1;
int j1 = *j; // j1 is now 50
Arrays are implemented as individual variables sequentially oriented in "slots" in memory, and an array is really just a pointer to the first slot. As such, *j is dereferencing j, which is currently pointing to the first element, resulting in 42. Doing j += 1 advances the pointer by one "slot", such that *j will now result in 50.
Now, back to f2. (*d)->ival is exactly like doing (**d).ival. This is very much like the simple example I gave above. The next line, (*d)++, is advancing the pointer to the next "slot". Consider this simple diagram of what's "happening" in memory:
+------+------+
|*(j+0)|*(j+1)|
j --->|------|------|
| 42 | 50 |
+------+------+
with j pointing to the first "slot", the dereference shown in the first row, the value in the second.
f3 is very much like f2, except that it expects the array to be passed as an argument, instead of a pointer to it. Hence, d only needs to be dereferenced once with the -> operator (again, exactly like (*d).ival).
f4is very much like f1, except that it expects the array to be passed as an argument, instead of a pointer to it. Hence, d[i] is directly accessing the i-ith element of the array.

void f1(data_t **d)
{
for (int i=0; i<MAXSIZE; i++)
{
(*d)[i].ival = i;
}
}
You get a pointer to array **d of data_t ,which element is a structure,having a field ival
Access the array *d
Iterate all array elements,element by element,changing indices i.And updating ival of each array element by to be i
Note:You dont change the pointer*d`,pointing to array beginning
void f2(data_t **d)
{
for (int i=0; i<MAXSIZE; i++)
{
(*d)->ival = i;
(*d)++
}
}
You get a pointer to array **d of data_t ,which element is a structure,having a field ival
Access the array *d,which is also a pointer to the array (first element)
Updating ival of the (above) element by to be i,using pointer notation (*d)->ival = i;
Promote the pointer to the next array element (*d)++ and return to 2.From now on *d is
pointing to the "sifted"array beginning.
void f3(data_t *d)
{
for (int i = 0; i<MAXSIZE; i++)
{
d->ival = i;
d++;
}
}
1.You get an array *d of data_t ,which element is sa structure,having a field ival.
2.It also can be considered you get a pointer to the first element of array.
Access access and update ival to be i,by pointer: d->ival = i;
3.Promote the pointer to the next array element d++
void f4(data_t *d)
{
for (int i = 0; i<MAXSIZE; i++)
{
d[i].ival = i;
d++;
}
}
As in f3.But you promote indices and update ival using reference notation (by value)

Related

Whether the element of an integer pointer array can pointer to an integer array?

I am wondering the ptr[i] pointer in the following code can be pointed to an integer array, why or why not. The problem is that if there exists another integer array (i.e. int brr[] = {4,5,6}), whether ptr[i] can be pointed to the integer array (i.e. brr)or it can just point to an integer(i.e. brr[i]), why or why not?
#include <stdio.h>
const int SIZE = 3;
void main()
{
// creating an array
int arr[] = { 1, 2, 3 };
// we can make an integer pointer array to
// storing the address of array elements
int i, *ptr[SIZE];
for (i = 0; i < SIZE; i++) {
// assigning the address of integer.
ptr[i] = &arr[i];
}
// printing values using pointer
for (i = 0; i < SIZE; i++) {
printf("Value of arr[%d] = %d\n", i, *ptr[i]);
}
}
An array decays to a pointer to its first element when used as an r-value. So
ptr[i] = arr;
is equivalent to
ptr[i] = &arr[0];
Since you already know that the latter is valid, so is the former.

creating pointer arrays in c++ with help of new keyword

What's the meaning of the code below?
int **matrix = new int*[n]
What's the difference here between matrix and int*[n]?
It is an array of 'n' pointers, for which memory can be allocated and initialized in loop.
If n is 3, it is an array of 3 elements and each is pointer to int, can point to set of array of integer values like below.
matrix[0] -> Ox001 points to array of int [ 1 2 3 4]
matrix[1] -> Ox017 [ 5 6 7 8]
matrix[2] -> Ox024 [ 9 10 11 12]
Sample code like this
int **m = new int*[3];
for(auto i=0; i < 3; i++)
{
m[i] = new int[3];
for(auto j=0; j < 3; j++)
m[i][j] = 0;
}
for(auto i=0; i < 3; i++)
{
m[i] = new int[3];
for(auto j=0; j < 3; j++)
cout << m[i][j];
cout << "\n";
}
for instance there is cricket team and you need
Since you have Cricket* team;, this indicates you have one of two possible
situations:
1) a pointer to a single CricketPlayer (or any derived) type
2) a pointer to an array of CricketPlayer (but not derived) types.
What you want is a pointer to an array of CricketPlayer or derived types. So you
need the **.
You'll also need to allocate each team member individually and assign them to the array:
// 5 players on this team
CricketPlayer** team = new CricketPlayer*[5];
// first one is a bowler
team[0] = new Bowler();
// second one is a hitter
team[1] = new Hitter();
// etc
// then to deallocate memory
delete team[0];
delete team[1];
delete[] team;
In your query,
It can be understood as
int *matrix[]=new int*[n];
SO there are n pointers pointing to n places.
Because
int *foo;
foo=new int[5];
will also create 5 consecutive places but it is the same pointer.
In our case it is array of pointers
You need to notice some thing as follows:
int *p means that p is a pointer that points to an int variable or points to an array of int variables.
int* *p means that p is a pointer that points to an int* variable or points to an array of int* variables.
new int[5] is an array of 5 int variables.
new int*[5] is an array of 5 int* variables.
In this case, matrix is the second type so it can point to an array of int* variables so the statement:int **matrix = new int*[n] is legal
It means that you have declared a double pointer(of type int) called matrix and allocated an array of n int* pointers. Now you can use matrix[i] as an int* pointer (0 <= i < n). Later you might want to allocate memory to individual pointers as well like matrix[i] = new int[size];(size is an int or more appropriately size_t)
matrix is an object of type int **. This type is a pointer to pointer to int.
On the other hand, int * is a type, a pointer to int.
The expression:
new int*[n]
creates n adjacent objects of type int * somewhere in memory and returns a pointer to the first of them. In other words, it allocates and constructs n pointers to int; and returns a pointer to the first. Since the first (and each of them) are int *, the pointer pointing to the first is, in turn, of type int **.
It would be absolutely clear if you remember the operator associativity and precedence.
Going by that int *[n] will be interpreted by compiler : as array of " n pointer to integers".(as [ ] has greater precedence than *, so for easy understanding, compiler interprets it that way.).
Now comming to other side int ** matrix is pointer to pointer.
When you created an array of pointer,you basically have the address of the first location ,here first location stores an pointer to integer.
So,when you are storing the address of the first address of such array you will need pointer to a pointer to point the whole array.
//code for passing matrix as pointer and returning as a pointer
int ** update(int ** mat)
{
mat[0][1]=3;
return mat;
}
int main()
{ int k=4;
int **mat = new int*[k];
for(auto i=0; i < k; i++)
{
mat[i] = new int[k];
for(int j=0;j<k;j++)
{
if(i==j)
mat[i][j]=1;
else
mat[i][j]=0;
}
}
mat=update(mat);
for(auto i=0; i < k; i++)
{
for(auto j=0; j < k; j++)
cout << mat[i][j];
cout << "\n";
}
return 0;
}

Pointers and multi-dimensional arrays questions

I am teaching myself C++ and and currently learning about multi-dimensional arrays. Below is the code I am using. Below the code are the questions/concepts I am having trouble with.
int main(){
const unsigned row = 4, col = 4;
int arr[row][col], cnt = 0;
for (int(*a)[col] = arr; a != arr + col; ++a){
for (int *b = *a; b != *a + col; ++b){
*b = cnt;
++cnt;
}
}
system("pause");
return 0;
}
in the first line of the for statement for (int(*a)[col] = arr;
a != arr + col; ++a). Why does the int(*a)[col] = arr; require
the [col] for the for loop to execute correctly?
in the first line of the second for statement for (int *b = *a; b != *a + col; ++b). Is *a not dereferencing the pointer?
The second for statement is unclear to me as to how it work. I understand which order it executes, but I am unclear about the relationship between the first for statement and the second for statement. any clarification for would be very helpful.
Pointers have a type that they point to. Except for void *, a pointer can only hold the address of an object of that type.
In the first line: Since you are looping over each row of the array, the pointer must point to a whole row (not to a single int).
In the second line, *a does dereference a. *a. is always equivalent to a[0]. Since a points to a row, a[0] designates that row.
a[0] is an array, so when it is used to initialize b, it decays to a pointer to the first element of that row.
The firs tlook loops over each row; the second loop loops over ech column. It's the same structure as:
for (int i = 0; i < row; ++i)
for (int j = 0; j < row; ++j)
arr[i][j] = ++cnt;
except you are using a pointer instead of an integer offset that is later added to a pointer.

C++ pointer to int in loops?

Ok, so I'm quite new to C++ and I'm sure this question is already answered somewhere, and also is quite simple, but I can't seem to find the answer....
I have a custom array class, which I am using just as an exercise to try and get the hang of how things work which is defined as follows:
Header:
class Array {
private:
// Private variables
unsigned int mCapacity;
unsigned int mLength;
void **mData;
public:
// Public constructor/destructor
Array(unsigned int initialCapacity = 10);
// Public methods
void addObject(void *obj);
void removeObject(void *obj);
void *objectAtIndex(unsigned int index);
void *operator[](unsigned int index);
int indexOfObject(void *obj);
unsigned int getSize();
};
}
Implementation:
GG::Array::Array(unsigned int initialCapacity) : mCapacity(initialCapacity) {
// Allocate a buffer that is the required size
mData = new void*[initialCapacity];
// Set the length to 0
mLength = 0;
}
void GG::Array::addObject(void *obj) {
// Check if there is space for the new object on the end of the array
if (mLength == mCapacity) {
// There is not enough space so create a large array
unsigned int newCapacity = mCapacity + 10;
void **newArray = new void*[newCapacity];
mCapacity = newCapacity;
// Copy over the data from the old array
for (unsigned int i = 0; i < mLength; i++) {
newArray[i] = mData[i];
}
// Delete the old array
delete[] mData;
// Set the new array as mData
mData = newArray;
}
// Now insert the object at the end of the array
mData[mLength] = obj;
mLength++;
}
void GG::Array::removeObject(void *obj) {
// Attempt to find the object in the array
int index = this->indexOfObject(obj);
if (index >= 0) {
// Remove the object
mData[index] = nullptr;
// Move any object after it down in the array
for (unsigned int i = index + 1; i < mLength; i++) {
mData[i - 1] = mData[i];
}
// Decrement the length of the array
mLength--;
}
}
void *GG::Array::objectAtIndex(unsigned int index) {
if (index < mLength) return mData[index];
return nullptr;
}
void *GG::Array::operator[](unsigned int index) {
return this->objectAtIndex(index);
}
int GG::Array::indexOfObject(void *obj) {
// Iterate through the array and try to find the object
for (int i = 0; i < mLength; i++) {
if (mData[i] == obj) return i;
}
return -1;
}
unsigned int GG::Array::getSize() {
return mLength;
}
I'm trying to create an array of pointers to integers, a simplified version of this is as follows:
Array array = Array();
for (int i = 0; i < 2; i++) {
int j = i + 1;
array.addObject(&j);
}
Now the problem is that the same pointer is used for j in every iteration. So after the loop:
array[0] == array[1] == array[2];
I'm sure that this is expected behaviour, but it isn't quite what I want to happen, I want an array of different pointers to different ints. If anyone could point me in the right direction here it would be greatly appreciated! :) (I'm clearly misunderstanding how to use pointers!)
P.s. Thanks everyone for your responses. I have accepted the one that solved the problem that I was having!
I'm guessing you mean:
array[i] = &j;
In which case you're storing a pointer to a temporary. On each loop repitition j is allocated in the stack address on the stack, so &j yeilds the same value. Even if you were getting back different addresses your code would cause problems down the line as you're storing a pointer to a temporary.
Also, why use a void* array. If you actually just want 3 unique integers then just do:
std::vector<int> array(3);
It's much more C++'esque and removes all manner of bugs.
First of all this does not allocate an array of pointers to int
void *array = new void*[2];
It allocates an array of pointers to void.
You may not dereference a pointer to void as type void is incomplete type, It has an empty set of values. So this code is invalid
array[i] = *j;
And moreover instead of *j shall be &j Though in this case pointers have invalid values because would point memory that was destroyed because j is a local variable.
The loop is also wrong. Instead of
for (int i = 0; i < 3; i++) {
there should be
for (int i = 0; i < 2; i++) {
What you want is the following
int **array = new int *[2];
for ( int i = 0; i < 2; i++ )
{
int j = i + 1;
array[i] = new int( j );
}
And you can output objects it points to
for ( int i = 0; i < 2; i++ )
{
std::cout << *array[i] << std::endl;
}
To delete the pointers you can use the following code snippet
for ( int i = 0; i < 2; i++ )
{
delete array[i];
}
delete []array;
EDIT: As you changed your original post then I also will append in turn my post.
Instead of
Array array = Array();
for (int i = 0; i < 2; i++) {
int j = i + 1;
array.addObject(&j);
}
there should be
Array array;
for (int i = 0; i < 2; i++) {
int j = i + 1;
array.addObject( new int( j ) );
}
Take into account that either you should define copy/move constructors and assignment operators or define them as deleted.
There are lots of problems with this code.
The declaration void* array = new void*[2] creates an array of 2 pointers-to-pointer-to-void, indexed 0 and 1. You then try to write into elements 0, 1 and 2. This is undefined behaviour
You almost certainly don't want a void pointer to an array of pointer-to-pointer-to-void. If you really want an array of pointer-to-integer, then you want int** array = new int*[2];. Or probably just int *array[2]; unless you really need the array on the heap.
j is the probably in the same place each time through the loop - it will likely be allocated in the same place on the stack - so &j is the same address each time. In any case, j will go out of scope when the loop's finished, and the address(es) will be invalid.
What are you actually trying to do? There may well be a better way.
if you simply do
int *array[10];
your array variable can decay to a pointer to the first element of the list, you can reference the i-th integer pointer just by doing:
int *myPtr = *(array + i);
which is in fact just another way to write the more common form:
int *myPtr = array[i];
void* is not the same as int*. void* represent a void pointer which is a pointer to a specific memory area without any additional interpretation or assuption about the data you are referencing to
There are some problems:
1) void *array = new void*[2]; is wrong because you want an array of pointers: void *array[2];
2)for (int i = 0; i < 3; i++) { : is wrong because your array is from 0 to 1;
3)int j = i + 1; array[i] = *j; j is an automatic variable, and the content is destroyed at each iteration. This is why you got always the same address. And also, to take the address of a variable you need to use &

Passing 2D array of const size

How should an array of constant size:
const int m = 5, n = 3;
int arr[m][n];
be passed to a function in a way which is both C89 and C++-compatible?
void func(const int m, const int n, int arr[][n]) { }
isn't valid C++ (giving errors such as "A parameter is not allowed" and "Variable 'n' was not declared in this scope"), even though the size of arr is determinate at compile-time. (It is valid C, however.) #defineing m and n works but is not preferred due to scope issues. Passing a pointer to the first element of the array leads to ugly code in the function body.
Feel free to take a look at this FAQ for context.
In C++, you can pass an array to a function with full type information intact by utilizing a template and an array reference function argument:
template <unsigned M, unsigned N>
void func (int (&arr)[M][N]) {
//...
}
The function prototype you are using is using a C99 feature called VLA to provide a dynamic binding of the array dimension. This is not a C++ feature, although some C++ compilers will allow it as an extension to the C++ language.
The C-FAQ was written before C99 was ratified, so the variable length array feature was not yet a standard feature of C. With a modern C compiler with VLA support, the function prototype you provided works just fine.
There is another alternative to use if you have an older compiler for which VLA support is not available. That is to treat the 2-D array as a flattened 1-D array, and use manual calculations to index the correct integer:
void func(const int m, const int n, void *p) {
int *a = p;
int i, j;
for (i = 0; i < m; ++i) {
for (j = 0; j < n; ++j) {
printf(" %d", a[i*n + j]);
}
puts("");
}
}
Then you call func(m, n, arr). In side the function, the expression
a[i*n + j]
steps over n ints i times, then steps over j ints. Since each row is n ints long, the calculation returns the ith row and the jth column, which corresponds precisely to arr[i][j].
I have tried this code:
void func(const int m, const int n, int arr[][n])
{
printf("%d\n", arr[4][2]);
}
int main()
{
const int m = 5, n = 3;
int arr[m][n];
arr[4][2] = 10;
func(m, n, arr);
}
and this work with no warnings
Your array arr[m][n] is not constant. However you have constant variables M and N. You should also define the arr[m][n] as a constant and not just an int array.
You may want to consider dynamicaly allocating your array so that you can just pass the pointer address down.
const int m = 5, n = 3;
int i = 0;
int* *arr; //Pointer to an integer pointer (Note can also be int **arr or int** arr)
arr = malloc(sizeof(int*)*(m+1)); //I add one because I am assuming that 'm' does not account for the terminating null character. But if you do not need a terminating null then you can remove this and the perantheses around the 'm'.
for(i = 0; i < m; i++)
{
arr[i] = malloc(sizeof(int*)*(n+1)); //Same as before
}
The inital malloc() call allocates memory for an array of integer arrays or said in another way, it allocates a pointer to a series of other pointers. The for loop will allocate an integer array of 'm' size for each element of the original array or said another way it will allocate space for every pointer address pointed to by the original pointer address. I left out error checking in order to simplfy my example but here is the same example with error checking.
const int m = 5, n = 3;
int i = 0;
int* *arr = NULL;
if((arr = malloc(sizeof(int*)*(m+1))) == NULL)
{
perror("ERROR(1): Failed to allocate memory for the initial pointer address ");
return 1;
}
for(i = 0; i < m; i++)
{
if((arr = malloc(sizeof(int*)*(m+1))) == NULL)
{
perror("ERROR(2): Failed to allocate memory for a subsequent pointer address ");
return 2;
}
}
Now that you have dynamicaly allocated your array you can just pass the pointer address.
int* *arr in the following the way.
void fun(const int n, const int m, int* *arr) {}
Also you don't necessarily have to keep track of the size of your arrays if the sizes are constant and if you use null terminated arrays. You just have to malloc the array using the constant integer variable's actual value and then check for the terminating null byte when iterating threw the array.
int* *arr = NULL;
if((arr = malloc(sizeof(int*)*6)) == NULL)'m'+1 = 6;
{
perror("ERROR(1): Failed to allocate memory for the initial pointer address ");
return 1;
}
for(i = 0; i < m; i++)
{
if((arr = malloc(sizeof(int*)*4) == NULL)//'n'+1 = 4
{
perror("ERROR(2): Failed to allocate memory for a subsequent pointer address ");
return 2;
}
}
You can then display the entire two dimensional array in the following way. Note that '\000' is the octagonal value for a null byte(00000000).
int i, j;
for(i = 0; arr[i] != '\000'; i++)
{
for(j = 0; arr[i][j] != '\000'; j++)
{
printf("%i ", arr[i][j]); //Prints the current element of the current array
}
printf("\n"); //This just ends the line so that each of the arrays is printed on it's own line.
}
Of course the above mentioned loops would have the same result as the following.
int i, j;
int m = 5;
int n = 3;
for(i = 0; i < m; i++)
{
for(j = 0; i < n; j++)
{
printf("%i ", arr[i][j]); //Prints the current element of the current array
}
printf("\n"); //This just ends the line so that each of the arrays is printed on it's own line.
}
Which means, in most situations there is no need for keeping track of an array's size but there are situations in which it is necessary. For example if one your arrays could possible contain a null byte other than the terminating null byte. The new null byte would shorten the array's size to the index of the new null byte. If you have any questions or comments feel free to comment below or message me.
The problem here is the "missing" support for dynamic arrays in C++.
const int m = 5, n = 3;
int arr[m][n];
Works since m and n are compile time constant and accessible directly at the declaration of the array.
void func(const int m, const int n, int arr[][n]) { }
The compiler handles your function regardless of where it is called in first place.
Therefore n is unknown/variable and thus prohibited as a array dimensionality.
The following example won't work too because of the very same reason:
void foo (const int n)
{
int arr[n]; // error, n is const but not compile time constant
}
int main (void)
{
foo(4);
}
jxh answered what to do about it.