Pointers allocate memory?

Hi!

If I do something like

void setup() {
  unsigned long* ul_p = 512;
  int* i_p = 1024;
  int a;
}

Will addresses 512 and 1024 be "as allocated" as &a? How can someone verify that?

Pointers are variables (16 bit address space on an Arduino Uno).

Dump RAM memory to see where the values end up.

No, you would create pointers to unallocated memory. In order to allocate you could do something like:

//Allocate
unsigned long *longptr = new unsigned long[1];
int *intptr = new int[1];

//Assignment
*longptr = 1234567;
*intptr = 12345;

//Release
delete[] longptr;
delete[] intptr;
1 Like

Serial.println(&a);

The Print class doesn't know how to print the value of a pointer. Depending on hardware platform you need either

Serial.print((uint16_t) &a);

or

Serial.print((uint32_t) &a);

Actually, to be correct C++, it should be:

  Serial.print(reinterpret_cast<uint16_t> (&a));
  Serial.print(reinterpret_cast<uint32_t> (&a));

What about:

Serial.print(reinterpret_cast<size_t>(&a));

for all platforms?

Serial.print(reinterpret_cast<uintptr_t>(&a));

size_t can store the largest object size, but not necessarily all pointer values.

1 Like

Interesting.

I assumed that size_t is necessarily the same size as *ptr_t because you can make an array that occupies the entire memory.

[edit]

After some reading: this assumption is apparently false on some architectures. Nice to know.

Thank you.

But how can you know that it would create pointers to unallocated memory? I didn't find anything that explain how it would behave. There is a way to test it?

As for the example, I agree that it would allocate memory, but I'm trying to keep control over an address without accessing it through a variable.

Thanks!

I'm not trying to print the addresses, but to make sure an address is allocated and accessing it through it's literal, not a variable.

I'm afraid you're thoroughly confused.

This is what you asked, print address of a and see if it matches your assigned addresses. However what you asked is also pointless

A pointer is just another type of variable. In C, you can assign any value to a pointer (if your try hard enough.)

On an AVR:
char *p = 1024; puts 1024 in the pointer, and gives you a pointer to some RAM location. It doesn't "allocate" that RAM location, so trying to use the value pointed to by the pointer may collide with something that DID allocate that location for some other variable.
char *p = 0xB0; puts 176 in the pointer, which happens to point to one of the peripheral registers for Timer2. This may be useful, and is used rather extensively to access such registers. It doesn't "allocate" anything, but the addresses are defined by the hardware, so they're
just there."
char *p = 0xF000; puts 0xF000 in the pointer, which makes it point to non-existent memory. Trying to access that memory will have unpredictable results (or a desktop, this will probably result in the famous "segmentation fault.")

The ability of C/C++ to treat arbitrary values as pointers is a great strength (accessing those peripheral registers without having to resort to assembly language), and a great danger.

2 Likes

So how do you find the runtime memory address of a variable? Say i had some weird memory mapped device (ever code 6800?) that i needed to peek and poke into a variable from the bottom up, as it were.

Use the Address of Operator.

I don't quite understand how those two sentences connect.
You get the address of a VARIABLE with the & operator, as several people have described.
But if you have a memory mapper peripheral, its address is probably dictated by the hardware, and that's when you start assigning numeric values to pointers directly.

Say you have "GPIO peripherals" whose register layout looks like:


It would be common to set up a C structure that directly maps to that:

typedef struct PORT_struct
{
    register8_t DIR;  /* Data Direction */
    register8_t DIRSET;  /* Data Direction Set */
    register8_t DIRCLR;  /* Data Direction Clear */
    register8_t DIRTGL;  /* Data Direction Toggle */
    register8_t OUT;  /* Output Value */
    register8_t OUTSET;  /* Output Value Set */
    register8_t OUTCLR;  /* Output Value Clear */
    register8_t OUTTGL;  /* Output Value Toggle */
    register8_t IN;  /* Input Value */
    register8_t INTFLAGS;  /* Interrupt Flags */
    register8_t PORTCTRL;  /* Port Control */
    register8_t reserved[5];
    register8_t PIN0CTRL;  /* Pin 0 Control */
    register8_t PIN1CTRL;  /* Pin 1 Control */
    register8_t PIN2CTRL;  /* Pin 2 Control */
    register8_t PIN3CTRL;  /* Pin 3 Control */
    register8_t PIN4CTRL;  /* Pin 4 Control */
    register8_t PIN5CTRL;  /* Pin 5 Control */
    register8_t PIN6CTRL;  /* Pin 6 Control */
    register8_t PIN7CTRL;  /* Pin 7 Control */
} PORT_t;

(where register8_t is also typedefed to volatile uint8_t or similar.)

Then you'd read the datasheet or talk to your HW engineer, to discover that PORTA is at 0x400, and PORTB is at 0x420, and do something like:

#define PORTA                (*(PORT_t *) 0x0400) /* I/O Ports */
#define PORTB                (*(PORT_t *) 0x0420) /* I/O Ports */
#define PORTC                (*(PORT_t *) 0x0440) /* I/O Ports */
#define PORTD                (*(PORT_t *) 0x0460) /* I/O Ports */

or perhaps

PORT_t *leds_port = 0x440;   // Blinky LEDs or PORTC.
leds_port->OUTSET = 0x10;    // set one of the LEDs.
// or
volatile uint_8_t *LEDS_TOGGLE = &(PORTC->OUTTGL);

(This is real close to way that the ATmega4809 include files define things, BTW. Not something I made up.)

And yeah, I had a college "microprocessors" class that was focused on 6800 (~1979?) I don't think I ever wrote any real programs (I was more of an 8085/8086/mainframe person), but I'm sure I did exercises and test questions! (Also since then I've done extensive programming of 68k, MIPS, PPC, and other architectures with memory mapped IO. Including typing in the structure definitions for ethernet controllers with MANY registers, since that was before such things were considered "support.")

1 Like

If you have a variable, you can use sprintf with the %p; below is basically what I use

sprintf(someBuffer, "%p", &someVariable);
sprintf(someBuffer, "%p", someArray);

That is the job of the MMU (Memory Management Unit). New pointers will always be created in unallocated memory, if there is not enough memory for the allocation, the returned pointer will either be null or an exception will be thrown - that depends on the MMU or the system.

When you write long *ptr = 1234 then "ptr" will be a pointer to memory address "1234" and the size of the memory pointed to is "sizeof(long)". But since the pointer is not allocated by the MMU, it may point to memory used by other parts of the code and that may cause unexpected behavior or havoc.

Testing whether a pointer points to valid memory is AFAIK not possible. Usually this should not be necessary at all when using good coding practices.

1 Like

There is no MMU in any of the CPUs used in Arduinos...