pesky pointer problems...

Hi, I’ve got a code problem that I suspect has got something to do with working with pointers. I started with a function with the following prototype…

 char* getPhone(byte num);

it’s purpose is very simple, I pass it a number and it returns a pointer to phone number from a list. If I pass a ‘1’ I get the first number from the list, a ‘2’ returns the 2nd number etc etc. I’ve used this function for ages and it seems to work fine.

I need a variation of this function that will return true or false depending on whether or not the phone number actually exists as well as returning a pointer to the number. This is needed for those occasions when the code asks for 3rd number in a list that only contains (for example) 2 numbers. This is what I came up with…

 bool ConfigMan::getPhone (byte num, char * crewPhone)
{
  crewPhone= getPhone (num);

  // Check that the length of the phone number is within acceptable limits
  if ((strlen(crewPhone) <= 7) || (strlen(crewPhone) > 15) )
  {
    // Phone number is too short (or long) to be plausable
    return false;
  }
  else
  {
    return true;
  }
}

This code also appears to work when I test it against the original version using the following code snippet…

 for (byte x =0;x<=3;x++)
    {
      crewNum=confData. getPhone (x);
      Serial.print("crew # <");Serial.print(x,DEC);Serial.print(">. Phone number is <");Serial.print(crewNum);Serial.println(">");
    }
    for (byte x =0;x<=3;x++)
    {
      if (confData. getPhone (x, crewNum) == true)
      {
        // crew number is available
        Serial.print("crew # <");Serial.print(x,DEC);Serial.print(">. Phone number is <");Serial.print(crewNum);Serial.println(">");
      }
      else
      {
        // crew number not valid
        Serial.print("crew # <");Serial.print(x,DEC);Serial.println(">. not valid / unavialable ");
      }
    }

I get the following results…

crew # <0>. Phone number is <+445554076240 >
crew # <1>. Phone number is <>
crew # <2>. Phone number is <>
crew # <3>. Phone number is <>
crew # <0>. Phone number is <+445554076240 >
crew # <1>. not valid / unavialable
crew # <2>. not valid / unavialable
crew # <3>. not valid / unavialable

So far so good, everything is behaving as I hoped. The catch is that when the getPhone() function is incorporated in a object that is then passed as an parameter to another function it stops working i.e. the pointer seems to point to some random memory location rather than the selected phone number.

In summary…
myObject.getPhone() seems to work.
myObject->getPhone() never works.

Sadly my knowledge of pointers is at best flakey. I’ve tried my normal technique of randomly inserting ‘*’s and ‘&’s with no success, I’m sure the solution is quite trivial, please can someone enlighten me?

Cheers

Can you post code that demonstrates this problem?

This doesn’t look good:

 bool ConfigMan::getPhone (byte num, char * crewPhone)
{
  crewPhone= getPhone (num);

crewPhone is local, it will not get passed back. You would need char ** or a reference.

Or, just keep the original function as is and return null if the phone number is not found.

To be more technical a local variable in C has local scope and dynamic extent - it ceases to exist when the enclosing function returns. Put another way C doesn't support closures (with closures all variables have indefinite extent - they exist for as long as they are referenced).

You could rewrite that function this way using pass-by-reference:

 bool ConfigMan::getPhone (byte num, char* &crewPhone)
{
  crewPhone= getPhone (num);

or even using explicit pointers:

 bool ConfigMan::getPhone (byte num, char* *crewPhone)
{
  *crewPhone= getPhone (num);

However the more elegant solution to your actual problem is to realise that you can return a null pointer from getPhone() to indicate no-match - just have the original getPhone () go "return (char*) 0 ;" if no match found

  if (crewPhone = getPhone (num))
  {
    // there was a result, so process it
  }

null ponters have the value zero, zero can be cast to any pointer type. "NULL" may already be #defined to 0

The whole project involves dozens of libraries and custom hardware so posting something that can easily be run on another arduino probably isn’t practical. The original getPhone() function is based on a library that reads from a file on an SD card. That library itself is then based on a dozen others. I’ll try to give an explanation here of how it all hangs together…

The two getPhone() functions are defined in the ConfigMan library…

char * ConfigMan::getPhone(byte num)
{
  // If the file isn't already open, then open it.
  if (opened == false)
  {
    // open the config file tracker.txt
    open();
  }

  // Look up the value for glider ID in the file tracker.txt
  sprintf_P(_tag,CREW_NO,num);
  _configFile.getTagValue(_tag,_tempTagVal);

  if ( strlen(_tempTagVal) != 0 )
  {
    // hmmmm...
  }
  close();
  return _tempTagVal;
}


/*
 * Same functionality as previous version, but validates the phone number and
 * returns true if it looks ok. Return false if the number doesn't exist or isn't
 * a sensible phone number.
 */
bool ConfigMan::getPhone(byte num, char* crewPhone)
{
  crewPhone=getCrew(num);

  // Check that the length of the phone number is within acceptable limits
  if ((strlen(crewPhone) <= _minPhoneLen) || (strlen(crewPhone) > _maxPhoneLen) )
  {
    // Phone number is too short (or long) to be plausable
    return false;
  }
  else
  {
    return true;
  }
}

The ConfigMan library is used in the Dispatcher library by a function with the following prototype…

byte processTop(ConfigMan* p_configMan, 
                       MessMan* p_messMan, 
                       MiniGPS* p_miniGps,
                       char *Id);

so the first parameter in processTop is a pointer to an object based on the ConfigMan library.
This function contains a pointer to a character array…
char * p_phoneNo;  // Pointer to phone number
and the following line…

if (p_configMan->getPhone(crewNum,p_phoneNo) == true)
      {
// do stuff
}

The above snipet is at the crux of the problem, when getPhone() returns true, p_phoneNo should point to a string array containing a phone number - it seems to actually point to a single random character.

In my top level arduino sketch I declare an object called ‘dispatch1’ of type Dispatcher…

Dispatcher dispatch1;

And an object called ‘configMan1’ of type ConfigMan…

ConfigMan confMan1;

I then invoke the processTop() function with the following line…

byte res=dispatch1. processTop (&confMan1, &mess1, &gps1,ID);

So I’m passing my Dispatcher object the address of my ConfigMan object.

Sorry I can’t post a simple working example (or even a simple not-working example) the only way could do this is by publishing the whole project and sending the hardware! I’m trying to work on a simple cut-down version of the code to publish but this may take some time.

You would need char ** or a reference.

Thanks Wildbill, I'm not being lazy here but could you please be a little more explicit about how to get this working, I've only just got my head around pointers() and addresses(&) and I'm not sure what char* means (is this a pointer to a pointer?). I've already spent some time expereimenting with char** but haven't got anything to work.

Or, just keep the original function as is and return null if the phone number is not found.

This is in fact what I've done, just to get my project working, but being a pig-headed so-and-so I'd still like to get the d4mn function to work!

what char** means (is this a pointer to a pointer?).

Yes

I'm guessing your post and MarkT's passed in the ether - there's more detail there. Post again if it isn't sufficient.

Thanks MarkT,

Thats exactly what I was looking for - I'll try your suggestions as soon as possible!

Cheers

BigusDickus:

You would need char ** or a reference.

Thanks Wildbill, I’m not being lazy here but could you please be a little more explicit about how to get this working, I’ve only just got my head around pointers(*) and addresses(&) and I’m not sure what char** means (is this a pointer to a pointer?). I’ve already spent some time expereimenting with char** but haven’t got anything to work.

Or, just keep the original function as is and return null if the phone number is not found.

This is in fact what I’ve done, just to get my project working, but being a pig-headed so-and-so I’d still like to get the d4mn function to work!

Just be careful to distinguish between the address-of operator ‘&’ and the reference declarator ‘&’ - the first means “take the address of this variable”, the latter means "this argument is to be passed by reference and in the body of the function access it via the supplied reference (in other words its not a local variable, its an “alias” for the variable passed in the call).