I am struggling to understand the code below, I understand that t is a multidimensional character variable ( 3 row and 3 columns), and p is a pointer or array of pointers, the array of pointers shouldn't be declared as:
int **p[3][3];
p= new int*[3]
instead of *p = (char *)t; Can someone help me to understand the meaning of this declaration?.. thanks in advance
#include <iostream>
using namespace std;
int main() {
char t[3][3], *p = (char *)t;
for(int i = 0; i < 9; i++)
*p++ = 'a' + i;
cout << t[1][1];
return 0;
}
char t[3][3] allocates 9 chars in memory, something like:
1 2 3 4 5 6 7 8 9
[ ][ ][ ][ ][ ][ ][ ][ ][ ]
Next you let the pointer p point to the first allocated char ( *p = (char * )t
1 2 3 4 5 6 7 8 9
[ ][ ][ ][ ][ ][ ][ ][ ][ ]
*p
Knowing there are 9 allocated chars, you can now move the pointer forward with the statement *p++, so after first *p++
1 2 3 4 5 6 7 8 9
[ ][ ][ ][ ][ ][ ][ ][ ][ ]
*p
Then you insert the char 'a'+i into that memory location
1 2 3 4 5 6 7 8 9
[ ][a][ ][ ][ ][ ][ ][ ][ ]
*p
1 2 3 4 5 6 7 8 9
[ ][a][b][ ][ ][ ][ ][ ][ ]
*p
and so on...
Note operator precedence is important, ++ (postfix) has higher precedence than * (inderection), so first the pointer is incremented by one (++), and then the inderection gives 'access' to the allocated memory, if you prefer to be more explicit about it, you can use *(p++) instead.
whats happening is that it's declaring the variable p as having the same pointer as your 2D array t. That way it can access it without requiring nested forloops.
'graphically' the contents would be accessed something like this:
pointer in question.
T
->1 2 3
4 5 6
7 8 9
P
->1 2 3 4 5 6 7 8 9
If you have an array like this
char t[3][3];
then pointer to its first element can be declared like
char ( *p )[3] = t;
That is the pointer p points to an object of type char[3]. If to increase the pointer ++p then the value in p will be increased by the value equal to sizeof( char[3] ) that is p will point to the second "row" of the array.
The value stored in p after this declaration
char ( *p )[3] = t;
is equal to the value of the expression &t[0][0]. The difference is the type of the objects pointed to by these pointers.
Thus you can write for example
char *p2 = reinterpret_cast<char *>( p );
So p2 and p have the same value but increasing the pointer p2 moves it "right" to point to the second character of the array while increasing the pointer p moves it "right" to point at once to the second "row" of the array.
So you can reinterpret the pointer p as a pointer of type chsr * to traverse the array character by character.
You can write either using C casting
char *p2 = (char *)t;
or using C++ casting
char *p2 = reinterpret_cast<char *>( t );
Related
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 5 years ago.
Improve this question
I found an example of std::vector in http://www.cplusplus.com/reference/vector/vector/data/.
// vector::data
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> myvector (5);
int* p = myvector.data();
*p = 10;
++p;
*p = 20;
p[2] = 100;
std::cout << "myvector contains:";
for (unsigned i=0; i<myvector.size(); ++i)
std::cout << ' ' << myvector[i];
std::cout << '\n';
return 0;
}
and the result is
myvector contains: 10 20 0 100 0
My question may be silly but I don't really understand what happened here. We got a direct pointer to the memory of the vector. Then we assign the value 10 for the first element (index 0), move to the second element and assign the value 20 to it (index 1). Finally, we assign the value 100 for the third element (index 2). Should the answer be as follow?
10 20 100 0 0
This picture might help explain
int* p = myvector.data();
[ ] [ ] [ ] [ ] [ ]
^
*p = 10;
[10 ] [ ] [ ] [ ] [ ]
^
++p;
[10 ] [ ] [ ] [ ] [ ]
^
*p = 20;
[10 ] [20 ] [ ] [ ] [ ]
^
p[2] = 100; // [2] is relative to where p is
[10 ] [20 ] [ ] [100] [ ]
^
The output of the example is right. Let me demonstrate it below -
std::vector<int> myvector (5); // creating vector with size 5, elements are 0,0,0,0,0
int* p = myvector.data(); //taking reference of the vector, p now points the first element of vector
*p = 10; // it means first element is now 10
++p; // p now points second element of the vector
*p = 20; // 2nd element is now 20
p[2] = 100; //p[2] is the 4th element now because of two position shifting and it is now 100
// vectors elements are now 10, 20, 0, 100, 0
std::vector<int> myvector (5); ==> [0,0,0,0,0]
int* p = myvector.data(); // p points to element 0
*p = 10; // element 0 is now 10
++p; // shift position of p to the next element
*p = 20; // element 1 is now 20
p[2] = 100; // Using p as reference, go 2 positions to right and assign the value of 100 to the element found at that position.
The output is correctly [10,20,0,100,0]
I'm tried to erase all elements from a vector. In fact, I wrote that:
#include<iostream>
#include<vector>
std::vector<int> foo(std::vector<int> v)
{
std::vector<int> result;
std::cout << "Initial size = " << v.size() << std::endl;
for(int i = 0; i < v.size(); i++)
{
std::cout << "Size = " << v.size() << std::endl;
v.erase(v.begin() + i);
}
return result;
}
int main()
{
int a[] = {1 ,2, 5, 8, 213, 2};
std::vector<int> v;
v.assign(a, a+6);
foo(v);
}
DEMO
Why does that program prints
Initial size = 6
Size = 6
Size = 5
Size = 4
Where is
Size = 3
Size = 2
Size = 1
?
After third erasure you have i == 3 and v.size() == 3 and for exits
You should learn to use the appropriate loop for what you want to achieve, or simply use them appropriately.
You can use a for loop when you know in advance how many iterations you need to do, but be careful with how you use the index.
What you're doing inside the cycle is changing the size of the vector, so every iteration v.size() becomes smaller. When i == 3, the vector size has been reduced to 3 and the loop ends earlier than you expected.
There are some alternatives to what you want to achieve,
// Store the size of the array so it doesn't change midway in the loop
for(int i = 0, iEnd = v.size(); i < iEnd; i++)
{
std::cout << v.size() << std::endl;
//v.erase( v.begin() );
v.pop_back(); // pop_back is quicker but erases from the end
}
Or
// More appropriate, since you don't even need to know the size
while ( !v.empty() ) {
std::cout << v.size() << std::endl;
v.pop_back();
}
In these loops I assume that you don't care about any specific elements and just want to erase them. If you do care about specific elements other answers already mention that.
But really you should be using
v.clear();
because the STL already does that for you.
To remove all elements from a vector use std::vector::clear
#include <iostream>
#include <vector>
using namespace std;
int main()
{
std::vector<int> v(10);
cout << v.size() << endl;
v.clear();
cout << v.size();
cin.get();
return 0;
}
When the 1st element is deleted v.size() is also updated.So when it reaches size 3 its size is also 3 so it exits the for loop.
Note: try not to use the update condition (the middle condition of for loop ) as something that changes as the loop proceed unless you are sure about doing it.
You can understand the problem easy if you consider this abstract loop
size_t N = v.size();
size_t i = 0;
size_t j = N;
while ( i < j )
{
i++;
j--;
}
Thus you will delete exactly ( N + 1 ) / 2 elements in the vector or more precisely ( v.size() + 1 ) / 2 elements .:)
To remove all elements in the vector you could use member function clear().
if you want to remove elements of the vector selectively you could write
for ( auto it = v.begin(); it != v.end(); )
{
if ( need_to_delete ) it = v.erase( it );
else ++it;
}
where need_to_delete is any condition you want to use.
Because after the 3 erasures (when Size = 4), v.size() is 3 and i is 3, so i < v.size() is no longer true and you break out of the for loop, for(int i = 0; i < v.size(); i++) and return from the function.
If you just want to erase all elements of a vector, try v.clear().
You may be aware of the concept of "iterator invalidation", and you are using size_t i to avoid this. Unfortunately, what you're using is still essentially an iterator and erasing an element from a vector invalidates all iterators not just the ::iterator typed ones :).
invalidate is a carefully chosen term that has subtle nuances. It implies that the iterators didn't stop working, and that you may sometimes find they still work. But you shouldn't trust them to.
So invalidate doesn't mean they are broken or wrong, it means that you should reconsider them. For example, if you have captured vec.begin() and you have caused the vector to relocate it's data, the value of vec.begin() may no-longer be valid. It typically isn't, but you've been warned :)
std::vector is implemented over a simple contiguous array:
[ 0 ][ 1 ][ 2 ][ 3 ]
When you erase an element, the object it contains is destructed and then all of the elements to the right are moved left, physically resituated in memory.
[ 0 ][~~~~~][ 2 ][ 3 ] sz=4
[ 0 ][ 2 << 2 ][ 3 ] sz=4
[ 0 ][ 2 ][ 3 << 3 ] sz=4
[ 0 ][ 2 ][ 3 ][?????] sz=4
Then the vector reduces size by the count of elements removed, in this case 1:
[ 0 ][ 2 ][ 3 ] sz=3
You can see that the overall process of erase(), then, is expensive when the objects are not simple or when the vector is large, but I'll come back to that.
The problem with your implementation is that you increase i, and the size shrinks, so you wind up deleting every second element.
i=0
[ 0 ][ 1 ][ 2 ][ 3 ] sz=4
erase(i);
i=0
[~~~~~][ 1 ][ 2 ][ 3 ] sz=3
[ 1 << 1 ][ 2 ][ 3 ] sz=3
[ 1 ][ 2 << 2 ][ 3 ] sz=3
[ 1 ][ 2 ][ 3 << 3 ] sz=3
[ 1 ][ 2 ][ 3 ][?????] sz=3
[ 1 ][ 2 ][ 3 ] sz=3
i=0
i++;
i=1
[ 1 ][ 2 ][ 3 ] sz=3
erase(i);
i=1
[ 1 ][~~~~~][ 3 ] sz=3
[ 1 ][ 3 << 3 ] sz=3
[ 1 ][ 3 ][?????] sz=3
[ 1 ][ 3 ] sz=2
i=1
i++;
i=2
[ 1 ][ 3 ] sz=2
break;
std::vector provides clear to empty an array, but if you are interested in understanding how to perform such an operation yourself:
Option 1: delete from back
while (!vec.empty())
vec.pop_back();
What this does is destruct the last element and then reduce size. It's very cheap.
[ 0 ][ 1 ][ 2 ][ 3 ] sz=4
pop_back();
[ 0 ][ 1 ][ 2 ][~~~~~] sz=4
[ 0 ][ 1 ][ 2 ] sz=3
Option 2: Erase a range of elements
std::vector<int> vec { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
vec.erase(vec.begin() + 2, vec.begin() + 5);
vec.erase(vec.begin(), vec.end());
Option 3: Shrink the array:
vec.resize(0);
Option 4: Clear
This is the preferred and normal way to empty a vector
vec.clear();
I have a weird problem going on. I have two functions, which both have an ofstream passed by reference. However when I call the second function, part of the first function is being printed.
Here is the first function:
void GamePlay::dealDominos(ofstream& outStream, int seed){
for(int i = 0; i < 10; ++i)
{
outStream << "random " << rand() << endl;
}
}
My second function is:
void GamePlay::findLongestSeq(ofstream& outStream)
{
outStream << toStringSeq(label, maxSeq) << endl;
}
However, my output looks like this:
NEW MAX [ T 0 8 ]
NEW MAX random [ T 0 8 ][ T 8 1 ]
NEW MAX ndom [ T 0 8 ][ T 8 1 ][ T 1 1 ][ T 1 2 ]
NEW MAX dom [ T 0 8 ][ T 8 1 ][ T 1 1 ][ T 1 2 ][ T 2 11 ]
MAX SEQ FOR: dom [ T 0 8 ][ T 8 1 ][ T 1 1 ][ T 1 2 ][ T 2 11 ]
I don't want the word "random" to be printed between the label and the sequence..
How do I fix this?
It looks like you've got two separate ofstream objects referring to the same underlying file, which is a pretty bad idea unless you're going to do lots of seek operations and flushes on every write, to ensure the file positions get updated for every write.
For code such as this:
std::list<int> a[3][3];
int myNumber = 0;
for(int i = 0; i < 3; i++)
{
for(int j = 0; j < 3; j++)
{
a[i][j].push_back(myNumber);
myNumber++;
}
}
The Local window of the debugger shows:
There is no easy way to go through and see that:
list a[ 0 ][ 0 ] contains 0
list a[ 0 ][ 1 ] contains 1
list a[ 0 ][ 2 ] contains 2
list a[ 1 ][ 0 ] contains 3
etc.
I can only see what lists [ 0 ][ 0 ], [ 1 ][ 0 ], and [ 2 ][ 0 ] contain but I want to see what all the lists contain. How do I go about doing this in Visual Studio 2010?
"There is no easy way to go through and see that list a[0][2] contains 2"
You right click somewhere into code, chose Quick Watch, write there a[0][2] and with Add Watch you put into "Watch 1" so that you can see your list<int> at a[0][2] properly.
When you declare simple list<int> l;, Visual Studio shows it properly. You are able to see all elements.
But when you declare array of lists like this:
std::list<int> l[2];
l[1].push_back(3);
l[1].push_back(4);
then variable l is considered pointer to first std::list<int> so even if you push elements into list at index 1, Visual Studio just shows you that l is empty list: some address [0](). I can see l[1] only if its in Watch:
Possible solution is to replace simple c-style array ([]) with std::vector :
std::vector<std::list<int> > l;
l.resize(2);
l[1].push_back(3);
l[1].push_back(4);
so l is not considered a pointer to first list anymore. Since l is vector Visual Studio displays you all elements properly:
I'd like to use the following function to return a transposed pointer to a multidimensional array.
Code
float** Matrix3f::Transpose( void )
{
float matrix[MATRIX3_DIMS][MATRIX3_DIMS] =
{
{ mMatrix[ 0 ][ 0 ], mMatrix[ 1 ][ 0 ], mMatrix[ 2 ][ 0 ] },
{ mMatrix[ 0 ][ 1 ], mMatrix[ 1 ][ 1 ], mMatrix[ 2 ][ 1 ] },
{ mMatrix[ 0 ][ 2 ], mMatrix[ 1 ][ 2 ], mMatrix[ 2 ][ 2 ] }
};
float** ret = new float*[ MATRIX3_DIMS ];
for ( int i = 0; i < MATRIX3_DIMS; i++ )
{
for ( int j = 0; j < MATRIX3_DIMS; j++ )
{
( *ret )[ i ][ j ] = matrix[ i ][ j ];
}
}
return ret;
}
Description
As shown, I declare a multidimensional array using initialization syntax(using the class-member matrix - mMatrix - to create a transposed version of the matrix itself. I then assign a multidimensional pointer to an array (ret) and loop through, assigning each member of the local array - matrix - to the ret pointer array.
The error I receive is the following:
error: invalid types ‘float[int]’ for array subscript
Question
What exactly am I doing wrong, and how can I accomplish this task?
ret is a pointer to pointer to float. When you dereference it, like this: (*ret), you get a pointer to float. When you take an index on that, like this: ( *ret )[ i ], that gives you a float. When you take an index on that, like this: ( *ret )[ i ][ j ], well, you're trying to index off of a float. That's not legal.
Putting my disgust for this style of coding aside, the first thing you're doing wrong is you are not allocating the sub-arrays. The compiler error though, refers to the error I illustrated in the first paragraph. Just remove the dereferencing of ret to fix that. You end up with this:
for ( int i = 0; i < MATRIX3_DIMS; i++ )
{
ret[i] = new float[MATRIX3_DIMS];
for ( int j = 0; j < MATRIX3_DIMS; j++ )
{
ret[ i ][ j ] = matrix[ i ][ j ];
}
}
This is totally not exception safe though, and you should be using a class that properly manages memory in an exception safe way, like std::vector.