Strings, strings, (const) characters, pointers - I'm confused

Hi,

First of all, I'm probably mixing up terms because I'm confused about this topic. Please don't be too harsh on me :slight_smile:

I'm working on some code that involves text (a url) to be sent to pushover.net.
I adapted code from this topic

The code involves Strings, strings(?), char, a pointer and piecing those together.

I'm not asking how to fix this code specifically but I hope someone can point me to a place where I can learn about the basics of these datatypes and why/how to use them. I haven't been able to find a source that explains the basic/general idea. So if you have a suggestion, thanks in advance.

Now for my code. This obviously doesn't work but I'm posting it to illustrate what I'm struggling with.

Thanks for reading!

EthernetClient poClient; 
char pushoversite[] = "api.pushover.net";
char apitoken[] = "a....................6";        // 30 characters
char userkey [] = "u....................m";       // 30 characters
int poMessageLength;

// Function call
pushTemperature("Current temperature is XX", 0);

// Function
byte pushTemperature(char *pushovermessage, int priority)
{
  char URL[] = "token=" + apitoken +
               "&user=" + userkey + 
               "&message=" + poMessage +
               "&sound=TemperatureAlert" + 
               "&priority=" + priority + 
               "&retry=60" + 
               "&expire=3600";

  poMessageLength = URL.length();
  
  Serial << "poMessageLength= " << poMessageLength << endl;

  if(poClient.connect(pushoversite,80))
  {     
      poClient.println("POST /1/messages.json HTTP/1.1");
      poClient.println("Host: api.pushover.net");
      poClient.println("Connection: close\r\nContent-Type: application/x-www-form-urlencoded");
      poClient.print("Content-Length: ");
      poClient.print(poMessageLength);
      poClient.println("\r\n");;
    
      poClient.print(URL);
    
      poClient.stop();
    }

 }

To my surprise, I actually have this code working now. However, it doesn't feel like this is the "proper" way. So I'd still like to learn more on the subject.

Thanks.

  String URL = "token=" + String(apitoken) +
               "&user=" + String(userkey) + 
               "&message=" + pushovermessage +
               "&sound=AlertOnTeensy" + 
               "&priority=" + String(priority) + 
               "&retry=60" + 
               "&expire=3600";

If you want to use the String class, what you have written in post #2 is fine. If you want to go for C strings, then the following may be of interest to you.

char URL[80];  // Make sure this array is large enough.
sprintf(URL, "token=%s&user=%s&message=%s", apitoken, userkey, poMessage);

Of course the last line should be longer, but you get the idea.

It's a lot for a beginner to try and understand... I'll try my best to explain.

char... a single character 'a' or 'A' or '1'... for example
char myChar = 'X';

string... more than one char (often referred to as a C-string in the Arduino world)... and needs to be terminated with a '\0' (null) character... so for example
char word [] = "abcde";
The '\0' is added automatically so the string above is actually 6 chars long. There are a bunch of standard C functions to handle strings.

pointer... this is actually not a type of variable. All variables are stored in memory... a pointer "points" to the location in memory of the variable. So this can be used to access the variable rather than it's name. Sometimes this can be really useful... you don't have to pass the variable itself.. you just pass the pointer.

String... well that's a bit more complicated. It's actually not just a variable, but a whole Class. It's like a string (as above), but comes with a bunch of built in methods to do stuff with the string. A lot of people on this forum don't like Strings... they can fill the memory if not used carefully.

3 Likes

Thanks,

I've actually been programming Arduino's for e few years now but it's like I'm stuck on "beginners level". So far I have managed to use workarounds and quick-and-dirty code. I would like to try to move on by for example understanding this topic.

I found this on the forum: The evils of Arduino Strings
More like this is welcome.

As an example why:
I posted I had the code working but I'm already running into the next thing. I would like to send the temperature that is read from another function. But this messy and ugly code doesn't work:

// Function call
String alertMessage = "Current temperature= " + String(getTemperature());
int alertMessageLength = alertMessage.length() + 1;
char charAlertMessage[alertMessageLength];
charAlertMessage = alertMessage.toCharArray(charAlertMessage, alertMessageLength);
pushTemperature(charAlertMessage, 0);

Please post the function code if you want help with that.. And, do you not get problems with this:

charAlertMessage = alertMessage.toCharArray(charAlertMessage, alertMessageLength);

String.toCharArray() does not return anything..

OK... this may start a holy war, but IMHO avoid using Strings and just use tried and tested C-strings (lowercase s... strings). Everything you can do with a String, you can do with a string... there are many standard C functions for manipulating strings. The implementation of the Arduino String class has dumbed down something that is actually not that hard to understand.

  char URL[] = "a bunch of text";
  poMessageLength = URL.length();

Note: A character array doesn't have a 'length' method. You could use C string functions:
poMessageLength = strlen(URL);
In this case you could use the array size but you have to remember that the array includes the terminator.
poMessageLength = (sizeof URL) -1;

Thanks for the replies.

For now I have "solved" the problems in my code by sticking with Strings (uppercase) and I got it working. The challenge is to do the same using strings (lowercase).

I have some reading to do and I'll have a go at it.

I'm not asking anyone to convert this code for me though hints are still welcome. The code below is like my starting point from now.

EthernetClient poClient; 
char pushoversite[] = "api.pushover.net";
char apitoken[] = "a................6";                       // 30 characters
char userkey [] = "u................m";                       // 30 characters
int poMessageLength;

// Function call
String alertMessage = "Current temperature = " + String(getTemperature()/10);
pushTemperature(alertMessage, 0);

// Function
byte pushTemperature(String AlertMessage, int priority)
{
  String URL = "token=" + String(apitoken) +
               "&user=" + String(userkey) + 
               "&message=" + AlertMessage +
               "&sound=TemperatureAlert" + 
               "&priority=" + String(priority) + 
               "&retry=60" + 
               "&expire=3600";

  poMessageLength = URL.length();

  if(poClient.connect(pushoversite,80))
  {    
    Serial << "connection ok" << endl;
    
    poClient.println("POST /1/messages.json HTTP/1.1");
    poClient.println("Host: api.pushover.net");
    poClient.println("Connection: close\r\nContent-Type: application/x-www-form-urlencoded");
    poClient.print("Content-Length: ");
    poClient.print(poMessageLength);
    poClient.println("\r\n");;
    
    poClient.print(URL);
    
    poClient.stop();
  }
}

You should read up on printf (print and format to stdout) and sprintf or snprintf (same as printf, but to a string). They make things a lot easier:

const char url_format = "token=%s&user=%s&message=%s&priority=%d";
#define BUFSIZE 100
...
char buffer[BUFSIZE]; //Must be large enought to hold everything
snprintf(buffer, BUFSIZE, url_format, apitoken, userkey, AlertMessage.c_str(), priority);
Serial.println(buffer);

Instead of buffering the URL, you could also just print the individual parts to the client:

client.print("token=");
client.print(apitoken);
client.print("&user=");
client.print(userkey);
client.print("&message=");
client.print(AlertMessage);
//And so on..

But that would require a different approach to calculate content length.

Thanks for the printf tip @Danois90

I haven't managed to convert my code yet, let's say it's work in progress.

I did read up on some topics though and it starts making sense.
For anyone finding this topic and struggling with the same issue, I found that the link I posted earlier is a nice starting point:
The Evils of Arduino Strings

Thanks again for your input to all.

EDIT: This is a reply to a post by 'GolamMostafa' that has been deleted.

Dude......seriously?! Really?!

I've seen way worse grammar and spelling on this forum.

Congratulations on making it to my blocklist :slight_smile:

1 Like

Meh. Don't take them too seriously. They incorrectly pluralized "input". They're hardly in a position to criticize your writing.

But, they do occasionally get the technical stuff correct.

2 Likes

A post was split to a new topic: Linear encoder from printer, can’t get it to work

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.