Taking a variable outside of Scope

I’m trying to write a piece of code that counts the number of commas in a string and returns that number as a global variable to the main code.

I won’t write the whole code but this is the crux of the problem:

string myString = “46,AB,2,90”

count = 0

i = 10 // this is the length of myString

for (int x = 0; x<i, x = x +1){

char n = myString.charAt(x);

if (n== ‘,’){

int count = count +1;

}

commaCount = count;

}

This just returns commaCount = 0. Even though count = 3 (within the scope of the if loop). How do I get it to return a new value for count, outside of the scope of the if loop?

This is the sort of thing I do in Matlab but I’m a noob to programming in C :slight_smile:

Thanks,

Chris

count = 0Sets a variable named count, presumably with global scope, but we can't tell from your code snippet, to zero.
  int count = count +1;A couple of problems here.
This declares a new variable named count with an unspecified value then tries to add one to it.
commaCount = count;This copies the value of the original count variable, which has not been changed, to another, presumably global variable.

Remove the int from

  int count = count +1;

To prevent a new variable with the same name being declared

Ah, yes it works now thanks. This is the final function:

int commaCountFunc(String GPS, int i){

int commaCount;
int count = 0;

for (int x = 0; x<i; x = x + 1){

char n = GPS.charAt(x);

if (n == ‘,’){

count = count + 1;

}
commaCount = count;
}

return commaCount;
}

Thanks!

It may work but it is untidy.

Why copy count to commaCount for each iteration of the for loop ? Come to that, why not just return count ?
More generally, why not calculate the length of the String in the function instead of passing it to the function ? Why use Strings at all when strings (zero terminated arrays of chars) would suit the microcontroller environment better ?

When you post code here please post whole programs and use [­code] ... [­/code] tags around the code.

And besides the above, if you insist in using Strings, use at least

int commaCountFunc(String& GPS, int i) {

to skip the unneccessary copy of the String object.

Thanks for the pointers everyone. I’ve tidied the code up to

int commaCountFunc(String myString){

  // Function that counts the number of comma delimiters in a string
  // String myString = "5,2,3,DS,589"   // Example String

  int commaCount;
  int count = 0;
  int i = myString.length();
  
   for (int x = 0; x<i; x = x + 1){
      
    char n = myString.charAt(x);
    
    if (n == ','){
      
     count = count + 1;
      
    }
  
  }
  
  return count;
}

You mention using this line instead for my function:

int commaCountFunc(String& myString)

But I’m not sure what difference the ‘&’ makes?

Will look into character array vs String. I’m not sure why char array is better for the micro controller? I use string because I think the GPS parsing only outputs in string format, but need to look into it.

But I'm not sure what difference the '&' makes?

The & operator is the address-of operator. That passes the address of a String instance, not a copy of the String instance.

I'm not sure why char array is better for the micro controller?

Is that a statement? Or a question?

Look at the WString.cpp file. Specifically, look at the += operator, or the concat() method, that the String class uses to add a character to the string it wraps. See where it uses malloc()? On a limited memory system, like the Arduino, that can cause memory fragmentation.

Imagine that you have a String instance that has grown to 20 characters. To add one more, you need to allocated space for the 20 you have plus the one to add. You have to copy the existing data to the new location and append the new character. Then, you free the previous location, leaving a 20 character hole in memory. Now, you want to add one more character. The 22 byte allocation will not fit in the 20 byte hole, so you need to look elsewhere. If you are lucky, the 22 byte chunk will be available. If not, well bad things happen but the String class can't tell you that.

If the allocation does succeed, and the existing 21 byte allocation is freed, and you are lucky, you have a 21 byte hole adjacent to a 21 byte hole, making a 41 byte hole that can be reused when you add the 23rd character. If not, you have a 20 byte hole and a 21 byte hole that can not be combined to satisfy a 23 byte allocation.

If you use, instead, a 80 byte array, adding another character is simply a matter of writing to the next position and incrementing the index.

Sure, sometimes (most, even) the array will be larger than actually needed. That just means that you need to decide on a maximum size for the array that is not too large or too small.

    char n = myString.charAt(x);
    if (n == ',')

Why use an intermediate variable ?

    if (myString.charAt(x) == ',')

PaulS:
The & operator is the address-of operator. That passes the address of a String instance, not a copy of the String instance.

No, technically not really, this use of & is to indicate pass by reference. Behind the scenes the address is passed, but this & is part of the parameter specification, not an operator.

Thanks for the input everyone, the function is a lot neater now.

I’m trying to write another function that returns the index of commas in a string as a array.

The function is as follows:

int commaIndexFunc(String& myString){
  // String myString = "99,500,,45,W,5";
  int myArray[0];
  int count = 0;
  for (int i=0;i<myString.length();i=i+1){

    if (myString.charAt(i) == ','){
    
    myArray[count] = i;
    //Serial.println(myArray[count]);
    count = count + 1;
    }
}
  return myArray;
}

Problem I’m having is how to call that function and access the array in my main code.

So I try something like this:

  int Ci[5] = {commaIndexFunc(GPS)};
  Serial.println(Ci[1]);

So I’m expecting to see it print the second number in that array (location 1).

But it doesn’t seems to work. Any thoughts?

I’m aware this could also be made as an additional output to my previous function but I also don’t know how to get a function to output two things like an integer and an array for example. I tried messing around with Struct but got into a bit of a mess :frowning:

Thanks,

Chris

  int myArray[0];Apart from anything else, this declares an array with no levels. Is that useful ?

This piece of code, not executed as a function seems to work:

string myString = “99,500,45,W,5”;

  int myArray[0];
  int count = 0;
  for (int i=0;i<myString.length();i=i+1){

    if (myString.charAt(i) == ','){
    
    myArray[count] = i;
    Serial.println(myArray[count]);
    count = count + 1;
    }
}

I think the dimensions of the array get updated in the for loop. int myArray is just declaring an empty array.

It seems when I want to put this in the form of a function and have it return myArray I get difficulties.

Any thoughts?

I cleaned up your code a little so it works and it compiled to 3118 bytes. I then wrote a new function using C strings (note lower-case ‘s’):

void setup() {

  //  string myString = "99,500,,45,W,5";   // Needs a capital 'S' in String
  char myString[] = "99,500,,45,W,5";

  Serial.begin(9600);
  Serial.print("The count is: ");
  //  Serial.println(commaIndexFunc(myString));
  Serial.println(modifiedCommaCounter(myString));
}

void loop() {

}

int modifiedCommaCounter(char str[]) {
  int count = 0;
  int i = 0;
  while (str[i]) {
    if (str[i++] == ',') {
      count++;
    }
  }
  return count;
}

/*
  int commaIndexFunc(String& myString) {

  //  int myArray[0];     // This defines nothing
  int count = 0;
  for (int i = 0; i < myString.length(); i = i + 1) {

    if (myString.charAt(i) == ',') {

  //      myArray[count] = i;   // This isn't going to work
  //      Serial.println(myArray[count]);
      count = count + 1;
    }
  }
  //  return myArray;   // Can't return an array
  return count;
  }
*/

which works the same, but uses only 1980 bytes. Most of us don’t like String objects because they eat a lot of resources and can lead to memory issues.

Chris102:
I think the dimensions of the array get updated in the for loop.

No. What makes you think so?

By writing outside the zero element array you open Pandora's box.

When you get to char arrays, finding elements within a string is trivial.
Look at all the strxxx() functions in C

Particularly strtok() and strchr() in this case.

Strings (big S) are a curse in a small memory environment- and often slower too.

size_t countChar(const char* psz, char const ch = ',')
{
    size_t count = 0;
    while ( *psz )
    {
        if ( ch == *psz++ )
        {
            count++;
        }
    }

    return count;
}


size_t numCommas = countChar("5,2,3,DS,589");

Whandall:
No. What makes you think so?

I thought this was working because it output each part of what I thought was a 1x5 array. But seems when I check the array size after the loop its still zero.

void setup() {

// put your setup code here, to run once:

String myString = “99,500,45,W,5”;
Serial.begin(9600);

int myArray[0];
  int count = 0;
  for (int i = 0; i < myString.length(); i = i + 1) {

if (myString.charAt(i) == ‘,’) {

myArray[count] = i;
        Serial.print("Comma Index: ");
        Serial.println(myArray[count]);
      count = count + 1;
    }
  }

int arrSize = sizeof(myArray)/sizeof(int);
Serial.print("myArray Size: ");
Serial.print(arrSize);

}

void loop() {
  // put your main code here, to run repeatedly:

}






Thanks for the char code, I'll see if I can avoid using strings with my GPS.