Problem with sizeof in a function

Greetings,
I am writing a small web server for a home automation system. I need to parse the HTTP header for the GET information so I thought to write a function to allow me to read an array of chars that is loaded when a client is connected. Below is a small program designed to test the function.

The function will be used to search the header and find the desired information and return the numeric value.

It compiles and runs; however, I get an incorrect sizeof for the passed parameter. No matter what is sent to it, sizeof returns a value of 2. I suspect that this is a pointer issue. I would be very grateful for any assistance.

char getstring[128]  = "GET /192.168.69.177?Page=43 HTTP 1.1";

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


void loop()
{ 
 Serial.println("***************");
 Serial.println(getparser("Page="), DEC);
 Serial.println("***************");
 
 while(1){} // Stops endless loop and runs function only once
}

int getparser(char findme[32])
{  
  Serial.print("Findme= ");          // Added for debugging
  Serial.println(findme);            // Added for debugging
  Serial.print("Sizeof Findme = ");  // Added for debugging
  Serial.println(sizeof(findme));    // Added for debugging
 
  for(int x = 0; x < 121; x++)
  {
   if(getstring[x] == findme[0])
   {
    int z = 0;
    for(int y = 1; y < sizeof(findme); y++)
    {
     if(getstring[x + y] == findme[y])
     { 
      if(z == sizeof(findme)) 
      {
        return ((((byte)getstring[x + y + 1] - 48) * 10) +
               ((byte)getstring[x + y + 2] - 48));
      }
      z++;
     }
    } 
   }
  }
  return 0;
}

No matter what is sent to it, sizeof returns a value of 2. I suspect that this is a pointer issue.

I don't know what you mean by "no matter what is passed in". All that IS passed in is a pointer, and pointers are all 2 bytes, regardless of the type of pointer.

You need to determine the size of the array where the array is defined, and pass that to the function that needs to know the size of the array.

Frankly, sizeof is the wrong way to determine the length of a string. strlen() is the proper way.

I think you misunderstand what sizeof() does - it returns the number of bytes that the data type of one instance of the argument uses.

example
char ch;
int igr;
long lng;

sizeof(ch) returns 1
sizeof(igr) returns 2 because integers are represented in two bytes
sizeof(lng) returns 4 because longs are represented in four bytes
etc.

The function to use to get the length of a string (not counting the terminating \0) is strlen().

strlen("Hello") would return 5

it returns the number of bytes that the data type of one instance of the argument uses.

So, what does

char lotsOfChars[100];
sizeof(lotsOfChars)

return?

How about

intlotsOfInts[100];
sizeof(lotsOfInts)

?

To be fair, the problem is caused by some extremely unintuitive behaviour of the 'C'/C++ language.

When you refer to a variable which is an array, the reference is syntactically equivalent to a pointer to the first element of the array, but the compiler knows the length of the array and sizeof(array) will give you the number of bytes occupied by the whole array.

When you refer to a function/method formal parameter which is an array, the reference is syntactically equivalent to a pointer to the first element of the array and the compiler has no knowledge of how long the array is; sizeof(array) will give you the size of the pointer. (In fact the array may be different each time the function/method is called; the array size is not a compile-time constant.)

To remove the potential confusion, it is better to explicitly declare function arguments as type pointer rather than type array - it is syntactically the same from the compilers point of view but clearer to the human reader.

PeterH:
To be fair, the problem is caused by some extremely unintuitive behaviour of the 'C'/C++ language.

When you refer to a variable which is an array, the reference is syntactically equivalent to a pointer to the first element of the array, but the compiler knows the length of the array and sizeof(array) will give you the number of bytes occupied by the whole array.

When you refer to a function/method formal parameter which is an array, the reference is syntactically equivalent to a pointer to the first element of the array and the compiler has no knowledge of how long the array is; sizeof(array) will give you the size of the pointer. (In fact the array may be different each time the function/method is called; the array size is not a compile-time constant.)

To remove the potential confusion, it is better to explicitly declare function arguments as type pointer rather than type array - it is syntactically the same from the compilers point of view but clearer to the human reader.

Thank you Peter. That is precisely the problem here. I am new to Arduino's and C/C++ though I have done some work with Basic Stamps and Picaxe's. Back in the 80's and 90's I programed in Pascal (A much more user friendly language than C/C++) and when I saw that sizeof was returning 2 no matter what string value I sent the function I thought that C was passing a pointer rather than creating the array of char's that Pascal would have done. So now that the problem has been correctly identified the question is. In C how do I find the length of the array of chars that the pointer references? I have been looking on the web, but not being a C programmer has been a hindrance in my key word searches.

Zathris:
So now that the problem has been correctly identified the question is. In C how do I find the length of the array of chars that the pointer references? I have been looking on the web, but not being a C programmer has been a hindrance in my key word searches.

See reply #1 and reply #2.

Arrch:

Zathris:
So now that the problem has been correctly identified the question is. In C how do I find the length of the array of chars that the pointer references? I have been looking on the web, but not being a C programmer has been a hindrance in my key word searches.

See reply #1 and reply #2.

Yes, I saw reply's #1 and #2. Both failed to address the problem. Only Peter had a grip on the issue. strlen() will not work because even if you try to type the input parameter as a string, the compiler passes a pointer to a constant char array. "error: cannot convert 'String' to 'const char*" So I typed the input as a char array. Then used the pointer to search out the the location in the HTTP header string and passed parameter. When I found a match and terminated with the "=" sign it then read the value data till it found a non numeric character and returned the result.

Here is the code that works. The only weakness is that you must have a search string that ends with a "=". But since everything I will be searching for in the HTTP header will be a Name=value format it should do nicely.

Thanks for the replies.
Zathris;

String getstring;

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

void loop()
{
 getstring = "GET /192.168.69.177?Page=03,Temp=98 HTTP 1.1";
 
 Serial.println(getstring);
 Serial.println("****************");
 Serial.println(parseget("Temp="));
 Serial.println("****************");
 
 while(1) {}  // To stop the endless loop and run the function only once
}

int parseget(char findme[24])
{  
  for(int x = 0; x < 121; x++)
  {
    if(getstring[x] == *findme)
    {
      for(int y = 1;(getstring[x + y] == *(findme + y)) ; y++)
      {
       if(*(findme + y) == '=')
       {
         int z = 1;
         int total = 0;
         while((byte(getstring[x + y + z]) > 47) && (byte(getstring[x + y + z]) < 58)) //Checks for numerals 
          {
            total = total * 10;  
            total += (byte(getstring[x + y + z]) - 48);
            z++;
          }  
         return total;
       }
      }
    }
  }
  return 0;
}

Zathris:
strlen() will not work because even if you try to type the input parameter as a string, the compiler passes a pointer to a constant char array. "error: cannot convert 'String' to 'const char*"

That doesn't make sense and makes me suspect you had a bug in your attempt to do this.

If you have a null-terminated array of bytes you can use strlen() to determine the number of characters before the null. If you're passing in something other than a null-terminated array of bytes, you can't use strlen().

Note that string (lowercase 's') and String (uppercase 'S') are completely different things so it's easy to get the wrong end of the stick when discussing them.

strlen() will not work because even if you try to type the input parameter as a string, the compiler passes a pointer to a constant char array. "error: cannot convert 'String' to 'const char*"

This is bullshit. You are incorrectly using string and String as though they are the same thing. They most certainly are not. If you have a string, a NULL terminated array of chars, then strlen() WILL determine the length, and the compiler won't complain.

If you have a String, then get yourself over to the documentation for the String class and figure out for yourself how to get the length of a String.

PaulS:

strlen() will not work because even if you try to type the input parameter as a string, the compiler passes a pointer to a constant char array. "error: cannot convert 'String' to 'const char*"

This is bullshit. You are incorrectly using string and String as though they are the same thing. They most certainly are not. If you have a string, a NULL terminated array of chars, then strlen() WILL determine the length, and the compiler won't complain.

If you have a String, then get yourself over to the documentation for the String class and figure out for yourself how to get the length of a String.

Sorry fellas, but it's not bullshit. Try it yourself. See if you don't get the error I got. It's a type cast issue. And why I never liked C in the first place.

String getstring;

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

void loop()
{
  getstring = "GET /192.168.69.177?Page=03 HTTP 1.1";
 
 Serial.println(getstring);
 Serial.println("****************");
 Serial.println(parseget("Page="));
 Serial.println("****************");
 
 while(1) {}
}
int parseget(String findme)
 {
   Serial.println(strlen(findme));
   return 0;
 }

Zathris:
Sorry fellas, but it's not bullshit. Try it yourself. See if you don't get the error I got. It's a type cast issue. And why I never liked C in the first place.

You realize the code you posted fits PaulS's description of what you're doing wrong perfectly, right? String and string aren't the same thing and determining the length is done differently.

Zathris:
Sorry fellas, but it's not bullshit. Try it yourself. See if you don't get the error I got. It's a type cast issue. And why I never liked C in the first place.

This compiles for me, once you get rid of the spurious use of the String class:

char *getstring;

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

void loop()
{
  getstring = "GET /192.168.69.177?Page=03 HTTP 1.1";

  Serial.println(getstring);
  Serial.println("****************");
  Serial.println(parseget("Page="));
  Serial.println("****************");

  while(1) {
  }
}
int parseget(char *findme)
{
  Serial.println(strlen(findme));
  return 0;
}

The output is:

GET /192.168.69.177?Page=03 HTTP 1.1


5
0


Which doesn't make a huge lot of sense, but in your original code you printed out the correct answer and then returned the wrong one and this does the same.

Arrch:

Zathris:
Sorry fellas, but it's not bullshit. Try it yourself. See if you don't get the error I got. It's a type cast issue. And why I never liked C in the first place.

You realize the code you posted fits PaulS's description of what you're doing wrong perfectly, right? String and string aren't the same thing and determining the length is done differently.

Obviously not. Perhaps rather than being condescending you might try being helpful. Explain why:

String getstring;
and
int parseget(String findme)

Are String and string. Both are typed as String are they not?

Yet another way of doing the same thing.

I get a lot of info here when I need to research:

Regards.

String getstring;

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

void loop()
{
  getstring = "GET /192.168.69.177?Page=03 HTTP 1.1";
 
 Serial.println(getstring);
 Serial.println("****************");
 Serial.println(parseget("Page="));
 Serial.println("****************");
 
 while(1) {}
}
int parseget(String findme)
 {
   int len;
   return findme.length();
 }

GET /192.168.69.177?Page=03 HTTP 1.1


5


Well the confusion is understandable.

string (lowercase s) is a term given to an array of char terminated by a \0 char

String (upercase S) refers to a class defined in the arduino core and is not the same thing.

see String() - Arduino Reference
and length() - Arduino Reference

RoyK:
Well the confusion is understandable.

string (lowercase s) is a term given to an array of char terminated by a \0 char

String (upercase S) refers to a class defined in the arduino core and is not the same thing.

see String() - Arduino Reference
and length() - Arduino Reference

OK, that helps to define terms. Thanks for the lack of condensation. However, it still doesn't help with the function in question. If I pass a constant string to the function (as the web server I am writing will consistently do) then strlen() doesn't work. What other way of mining the data would you suggest?

The strlen() function only works on char arrays, not String objects. String objects have their own built in length() method that returns the length of their string.
PeterH showed an example of how to use strlen with char arrays.
cbaldan showed an example of how to use the length() method of the String class.

If you try using strlen() with a String object, it isn't going to work.
If your char array isn't properly null terminated, strlen() isn't going to work.

If you have code using strlen() with a null terminated char array, and you aren't getting the result you expect, post it so we can see what the issue is.

Zathris:

Arrch:

Zathris:
Sorry fellas, but it's not bullshit. Try it yourself. See if you don't get the error I got. It's a type cast issue. And why I never liked C in the first place.

You realize the code you posted fits PaulS's description of what you're doing wrong perfectly, right? String and string aren't the same thing and determining the length is done differently.

Obviously not. Perhaps rather than being condescending you might try being helpful. Explain why:

String getstring;
and
int parseget(String findme)

Are String and string. Both are typed as String are they not?

I'm not sure how I can explain this any better.

You are using String objects in your code. There are no strings in your code. You're trying to use a function that accepts a string as an argument, but you are trying to send it a String object as the argument.

Both are typed as String are they not?

Both of what? The variable and the argument are typed as String. But, no matter how many times you assert that a String object and a NULL terminated array of chars, also known as a string, are the same thing, you are still wrong. They are most definitely NOT.

If a function, such as strlen() expects a string, you can NOT pass it a String. The compiler simply won't let you. Get over it. Ditch the String class, and learn to program like a big boy.