|
Richard MacCutchan wrote: If you want to pass a single int, char etc, then why use a pointer? Because it might inadvertently be nullptr , and I find this defensive code jarring:
void f(type& t)
{
if(&t ! nullptr)...
} The optimize-everything crowd won't agree, but in my opinion code that invokes the above with a null reference should suffer a SIGSEGV before the function is called. But since that's not the case...
|
|
|
|
|
I don't think a reference can ever be null.
|
|
|
|
|
It's true that C++ has no explicit notion of a null reference. But if you run this
void test(int& i)
{
if(i == 1)
std::cout << i << '\n';
}
int main(int argc, char* argv[])
{
int* pi = nullptr;
test(*pi);
} it will SIGSEGV on the line if(i == 1) . That's in a VS2017 debug build.
|
|
|
|
|
That is interesting. It should really crash at the test(*pi); line, since it is trying to dereference a null pointer. I would also suggest the the compiler should recognise that pi is a pointer and not a reference.
|
|
|
|
|
I agree that it should crash there. But I've never seen it work that way, though for most of my career I worked in a language where it would have crashed there.
It's not unusual to dereference a pointer (pi ) and pass it to an argument that wants a reference.
|
|
|
|
|
Greg Utas wrote: It's not unusual ... Interesting, but not something I have ever done. I had (naively) assumed that the whole point of references was to avoid this very trap. Incidentally I tried it in g++ as well and the gave a SEGV.
|
|
|
|
|
Where did it die in g++? Before or after calling the function?
|
|
|
|
|
Same as in Windows, on the if statement in test function.
|
|
|
|
|
Ditto for clang 9.0.1 (Fedora fc31)
Keep Calm and Carry On
|
|
|
|
|
Richard MacCutchan wrote: f you want to pass a single int, char etc, then why use a pointer?
On occasion you want an "out" or sentinel parameter, so in those cases you have to use a pointer (or a reference if using C++).
There's lots of cases where you might have a pointer to a single struct that you either want to fill in, or avoid copying the whole thing to the stack. For the latter, of course, you'd mark it as const .
Keep Calm and Carry On
|
|
|
|
|
how do you declare and access an array of pointers? if you want to cycle through pointers of same type in a for loop.
int * somedata[] = new int * [5]; ??
"DreamLand Page" on facebook
modified 29-Mar-20 14:42pm.
|
|
|
|
|
In that case you'd use another level of indirection: e.g.
#include <iostream>
void myfn(int **data, size_t len)
{
for(size_t i = 0; i < len; ++i)
*data[i] = i * 2;
}
int main)_
{
int data[5] = { 1, 2, 3, 4, 5 }; const size_t ndata = sizeof(data)/sizeof(data[0]);
int** pdata = new int*[ndata];
for(size_t i = 0; i < ndata; ++i)
pdata[i] = &data[i];
std::cout << "Before:\n";
for(size_t i = 0; i < ndata; ++i)
std::cout <^lt; *pdata[i] << std::endl;
myfn(pdata, 5);
std::cout <*lt; "\nAfter:\n";
for(size_t i = 0; i < ndata; ++i)
std::cout << *pdata[i] << std::endl;
delete[] pdata;
return 0;
}
Keep Calm and Carry On
modified 29-Mar-20 17:49pm.
|
|
|
|
|
|
This array of pointers thing is above trivial. Here is my old code:
CUSTOMVERTEX* ScreenLetters;
ScreenTextBuffers[0]->Lock( 0, 0, (void**)&ScreenLetters, 0 );
int LetterVertexDataincrement = 0;
int letterwidth = 12;
int letterheight = 12;
for(int ii = 0; ii < ScreenLetterGroups[0].height;ii++)
{
for(int i = 0; i < ScreenLetterGroups[0].width;i++)
{
ScreenLetters[LetterVertexDataincrement].position.x = i * letterwidth + ScreenLetterGroups[0].x;
ScreenLetters[LetterVertexDataincrement].position.y = ii * letterheight + ScreenLetterGroups[0].y;
ScreenLetters[LetterVertexDataincrement].position.z = 20;
ScreenLetters[LetterVertexDataincrement].color = 0xffffffff;
}
}
ScreenTextBuffers[0]->Unlock();
I have this piece of code repeating for every ScreenTextBuffers element. I want to place it in a `for` loop so what I`m doing is:
CUSTOMVERTEX ** ScreenLettersP_s = new CUSTOMVERTEX* [NumberOfTextBuffers];
int LetterVertexDataincrement = 0;
int letterwidth = 12;
int letterheight = 12;
for(int iii =0; iii < NumberOfTextBuffers; iii++)
{
ScreenTextBuffers[iii]->Lock( 0, 0, (void**)&ScreenLettersP_s[iii], 0 );
for(int ii = 0; ii < ScreenLetterGroups[iii].height;ii++)
{
for(int i = 0; i < ScreenLetterGroups[iii].width;i++)
{
*ScreenLettersP_s[LetterVertexDataincrement]->position.x = i * letterwidth + ScreenLetterGroups[iii].x;
*ScreenLettersP_s[LetterVertexDataincrement]->position.y = ii * letterheight + ScreenLetterGroups[iii].y;
*ScreenLettersP_s[LetterVertexDataincrement]->position.z = 20;
*ScreenLettersP_s[LetterVertexDataincrement]->color = 0xffffffff;
}
}
ScreenTextBuffers[i]->Unlock();
}
but it doesn`t compile, I`m getting an `illegal indirection` error
struct CUSTOMVERTEX
{
D3DXVECTOR3 position;
D3DCOLOR color;
FLOAT tu, tv;
};
modified 1-Apr-20 6:03am.
|
|
|
|
|
Arrays of pointers are just as trivial as arrays of anything, if you understand how to address them.
fearless_ wrote: I`m getting an `illegal indirection` error Since we cannot see your screen we also cannot guess where that occurs. Please format your code properly and explain exactly where the error occurs.
|
|
|
|
|
I get illegal indirection at this spot
*ScreenLettersP_s[LetterVertexDataincrement]->position.x = i * letterwidth + ScreenLetterGroups[i].x
|
|
|
|
|
The variable ScreenLettersP_s is an array of pointers, so the reference ScreenLettersP_s[LetterVertexDataincrement] is one of the actual pointers. The leading asterisk on ScreenLettersP_s means an extra level of indirection which is not required (or valid).
|
|
|
|
|
so this is specific for structures only. because if I change *data[i] = i * 2; to data[i] = i * 2; in the k5054s example I will be editing the save entry rather than the save data.
|
|
|
|
|
No. Pointers are pointers whatever they point at, be it an array or a structure. Think about a piece of memory as a sequence of cells. So a pointer to any cell allows you to access all the following cells in order, by using an index (pointer plus offset). If you (the programmer) have decided that the area you point to should be treated as if it contains different sized blocks (aka a structure), that does not affect the physical properties of the memory. It merely allows the compiler to calculate the distance between the elements of the structure. And an array of pointers is much the same thing.
If you have trouble visualising multi levels of indirection, then always go for a single level. If you have an array of pointers, then create a temporary one and allocate an array entry to it like:
CUSTOMVERTEX ** ScreenLettersP_s = new CUSTOMVERTEX* [NumberOfTextBuffers]; CUSTOMVERTEX* pTemp = ScreenLettersP_s[0]; pTemp->
|
|
|
|
|
I understand. for the record that`s directx 9.
|
|
|
|
|
fearless_ wrote: directx 9 I have not used DirectX, but I have used plenty of other Windows' functions that use structures, arrays of structures, and even arrays of structures that contain other unstructured structures. In the latter case, the presence or absence of certain items depends on settings elsewhere.
|
|
|
|
|
You have a vast experience, I appreciate all your help.
|
|
|
|
|
fearless_ wrote: You have a vast experience ~Far from it, what I don't know would fill many books.
But given that I know some stuff, I am happy to help.
|
|
|
|
|
So is this pointer a save of the physical address of the real thing or just an artifice done by the compiler which matches the data behind the scenes to achieve the desired result?
|
|
|
|
|
It is the actual address in the pointer. In that way you can address any array, or any structure just by passing the real address to the function.
void myFunc(char* someData, int length)
{
for (int i = 0; i < length; ++i)
{
char c = toUpper(someData[i]);
someData[i] = c; }
}
You can now call that function with any array of any length and get it converted.
In every case the function receives the physical address of the array and accesses each
character by using the index value i , where 0 <= i < length .
|
|
|
|