Array pointer conventions and consternations with Photon

I’ve been having a heck of a time trying to get some array pointer operations operational… there’s a really good writeup online that documents the flexibility and inter-expressional nature of array/pointer operations.

I’ve found the Particle environment doesn’t operate with most of what’s cited by my link, and in fact I’ve only managed to make this work using the following variant of code snippet on my Photon:

void acquireFrontChannel()
{
  int raw_Samples[3000];
  int *p;
  p = raw_Samples;
  for (int i = 0; i < 3000; i++)
  {
    *p = analogRead(0);
    Serial.printlnf("Local Pointer Array Element %d = %d", i, *p);
    *p = *(p + 1);
  }
}

What I’m really wanting to do is use the array pointer p with other functions and procedures that I’d call within the scope of this snippet, however ANY operations using this pointer as such causes an instant STACK-OVERFLOW.

This failure suggests there’s a context of this environment I don’t understand. I’m currently at wits end trying to make it work, so I’m putting this out to the community for a potential assist.

Any ideas?

your local variables 1) raw_Samples and 2)p are destroyed when the function ends. Just like i is destroyed when your for loop ends.

the tutorial doesn't really go into variable scope

1 Like

Right, this I understand…

Using it in scope of the code snippet, it fails as described.

  1. Assigning pointer p to a statically instantiated *int p
  2. Passing pointer p as a function argument (*int p) (note: only usage of passed argument will bomb things)

I would suggest that trying to learn C pointers on a small micro like this is harder than learning them on a PC/Linux/Mac since when things go south, you get less information and recovering is more difficult. But if you insist…

@BulldogLowell explained why having raw_Samples and p in the scope of the function means that they don’t exist anymore when you leave the function and you seem to be saying that if you hoist their definitions to (say) global scope and pass in the pointer, you still have problems.

One thing to consider is where does p point to after you are finished with your loop? Well, I will tell you that it points to some other variable off the end of your array. Are you resetting p to the start of the array before you try to use it again?

If you want more help, show us all your current code and we can help you better.

2 Likes

I agree with you @BKO, however my motivation in making this work is to save on memory space using what should be a fairly academic procedure.

I want raw_Samples[] to be allocated dynamically so when I’m done with my anaysis of the raw sample data and I have collected my results, it’s disposed.

To illustrate how it fails, let me illustrate the failing behavior in the code snippet:

int *ptr1;

void operateOnSamples(int *ptr2)
{
  for (int i = 0; i < 3000; i++)
  {
    if (*ptr2 > 1000) doSomething();  <-- **any operation with *ptr2 causes Stack Overflow**
    *ptr2 = *(ptr2 + 1);
  }
}

void acquireFrontChannel()
{
  int raw_Samples[3000];
  int *p;
  p = raw_Samples;

  // prove this runs locally in this scope
  for (int i = 0; i < 3000; i++)
  {
    *p = analogRead(0);
    Serial.printlnf("Local Pointer Array Element %d = %d", i, *p);
    *p = *(p + 1);
  }

  ptr1 = raw_Samples;  <-- ** this assignment causes Stack Overflow**

  p = raw_Samples;
  operateOnSamples(p);
}

Here’s the project complete for “cut and pastry”…

Enable either of the failure inducing mechanisms by un-commenting:

/*
 * Project ArrayPointerProject
 * Description:
 * Author:
 * Date:
 */

#include "Particle.h"

int *ptr1;

void setup() {
  Serial.begin(9600);
}

void clipHighSamples(int *ptr2)
{
  for (int i = 0; i < 3000; i++)
  {
    if (*ptr2 > 1000) *ptr2 = 1000;
    *ptr2 = *(ptr2 + 1);
  }
}

void acquireFrontChannel() {
  int raw_Samples[3000];
  int *p;
  p = raw_Samples;

  // prove this runs locally in this scope
  for (int i = 0; i < 3000; i++)
  {
    *p = analogRead(0);
    Serial.printlnf("Local Pointer Array Element %d = %d", i, *p);
    *p = *(p + 1);
  }

  //ptr1 = raw_Samples;

  //p = raw_Samples;
  //clipHighSamples(p);
}

void loop() {
  acquireFrontChannel();
  delay(3000);
}

if you create a variable in a function, that variable persists as long as the function.

So when passing a pointer to another function, you are guaranteed that pointer is “static” in that context.

like this:


void setup(void)
{
  Serial.begin(9600);
  acquireFrontChannel();
}

void loop()
{
  
}


void operateOnSamples(int *ptr2)
{
  for (int i = 0; i < 10; i++)
  {
    Serial.print(F("function says..."));
    Serial.println(*ptr2);
    ptr2++;
  }
}

int* ptr1;

void acquireFrontChannel()
{
  int raw_Samples[10];
  int* p = raw_Samples;

  for (int i = 0; i < 10; i++)
  {
    *p = analogRead(0);
    Serial.println(*p);
    p++;
  }

  ptr1 = raw_Samples;  //<-- ** this assignment causes Stack Overflow**

  p = raw_Samples;
  operateOnSamples(p);
}

1 Like

Thanks @BulldogLowell

First, is there verbiage missing from your statement “if you create a variable in a function, that variable persists as long as the function…(verbiage)? I’m just not 100% clear reading this, " as long as the function” part.

Second, are you saying that function variables when instantiated by an initial call in setup() makes them static? This is exactly what I don’t want (static allocation of raw sample arrays as I’m making big sample reads).

Thanks for helping me out…

that's all of it. when the function ends, the local variables are destroyed.

what is a function variable? I called the function from setup so that it would only one once for the sake of the example.

all of the standard rules of C++ variable scope apply...

Side Note: you can create local persistent variables in a function (or a block) using the aptly named static keyword

did the example help?

1 Like

Yes, I understand the scoping of local variables.

Sorry, I misinterpreted your reply… I’m gonna try your sample.

I’m certain it works as you’ve included, but the only real difference I’m seeing in my example vs. yours besides the minor reference tweaks is acquireFrontChannel() is invoked once in setup() vs. my repeated invocation loop()…

What am I missing, and sorry to be so dense on this…

how did you increment a pointer through your array?

*p = *(p + 1);

how did I?

function moved to loop():


void setup(void)
{
  Serial.begin(9600);
  
}

void loop()
{
  acquireFrontChannel();
  delay(500);
}


void operateOnSamples(int *ptr2)
{
  int* ptr3 = ptr2;
  for (int i = 0; i < 10; i++)
  {
    Serial.print(F("function says..."));
    Serial.println(*ptr3);
    ptr3++;
  }
}

int* ptr1;

void acquireFrontChannel()
{
  int raw_Samples[10];
  int* p = raw_Samples;

  for (int i = 0; i < 10; i++)
  {
    *p = analogRead(0);
    Serial.println(*p);
    *p++;
  }

  ptr1 = raw_Samples;  //<-- ** this assignment causes Stack Overflow**

  p = raw_Samples;
  operateOnSamples(p);
}
1 Like

Thanks again… gotta run now, but my pointer iteration sample was the only one that worked as I recall. I’ll monkey with these examples later tonight.

Just to add my two cent.
@jimini, what exactly do you intend to do with this instruction block?

You create a local/automatic array (not quite what "dynamically allocated" would mean in C/C++ jargon - that'd be heap based) with 3000 elements but your pointers only act on the the elements 0 & 1 :confused:

You don't seem to push your pointer p on to actually fill the array.

Also

Have you actually confirmed that the assignment itself causes the stack overflow and not only the effects of that assignment cause this to happen? And how?

BTW, when declaring an automatic/local int[3000] you actually gobble up almost 12KB of stack space since automatic/local variables (along with function parameters, return value and return address) will be stored there for the duration of the functions lifespan.
Depending on your actual call depth in production code, you may well run the risk of "unpredictable" stack overflows anytime.

1 Like

Hammer hits nail on head @ScruffR ... :hammer:

I suspected a stack/thread/context constraint as nothing else made sense... I actually kept a log of all the array/pointer code variants I tried and I was spoofed into thinking the example I posted did in fact operate. It gave the appearance of operation, but shrinking the array object proved it was indeed a false positive. "Unpredictable", non-determinant operations was indeed the case, and stack overflow determination was from the SOS blink pattern...

Has anyone a cite into more of the constraints of this stack/thread/context?
Thanks again to everyone for the assist...

1 Like