PVOID pAddress = Buffer; // A pointer that does not say what it holds (bytes, integers or a structure)
You cannot read or write directly through a PVOID; you have to state the data type
c
PVOID pAddress = Buffer;
PBYTE pBytes = (PBYTE)pAddress; // "treat this address as bytes"printf("First byte: 0x%02X\n", pBytes[0]); // prints 0x41
This is very common on Windows: functions such as VirtualAlloc return a PVOID (untyped memory) and you decide how to interpret it.
NULL: "points to nothing"
c
int* pValue = NULL;
It is address 0
c
if (pValue != NULL)
{
printf("%d\n", *pValue); // only if it points to something
}
You see it a lot on Windows
c
PBYTE pBuffer = (PBYTE)VirtualAlloc(NULL, 4096, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (pBuffer == NULL)
{
return FALSE; // the allocation failed, stop here
}
GOOD HABITS
c
int* p = NULL; // 1. Always initialise to NULL
...
free(p);
p = NULL; // 2. After freeing, set it back to NULL
Structures
A way of grouping several related pieces of data into a single package
c
typedefstruct _READER_INFO {
int Id;
int Age;
char Initial;
} READER_INFO, *PREADER_INFO;
_READER_INFO: The original "tag" of the structure. Analogy: the technical name of the mould
READER_INFO: An alias for the structure. Analogy: the handy name of the mould
PREADER_INFO: An alias for a pointer to the structure. Analogy: the address where a record card is
typedef is used to create aliases. Without it you would have to write struct _READER_INFO every time;
These two lines mean exactly the same:
c
struct _READER_INFO Card1; // long form
READER_INFO Card2; // short form (the usual one)
Windows uses this style in all its headers: PROCESSENTRY32 / PPROCESSENTRY32, STARTUPINFOW / LPSTARTUPINFOW, etc.
Initialising:{ 0 }
c
READER_INFO Card = { 0 }; // the card, with every field set to zero
PREADER_INFO pCard = NULL; // a pointer that does not point to any card yet
Here is the key rule, and it is very simple:
If you have the structure, you use the dot.
If you have a pointer to the structure, you use the arrow->
c
READER_INFO Card = { 0 };
Card.Id = 1470; // I have the card → dot
Card.Age = 34;
PREADER_INFO pCard = &Card; // pCard points to Card
pCard->Id = 8765; // I have a pointer → arrowprintf("%d\n", Card.Id); // prints 8765, because pCard points to the same card
These two lines are identical:
c
pCard->Id = 8765;
(*pCard).Id = 8765; // "go to where pCard points, and from that card take Id"