Difference between String and Array?

Im confused, what's the difference between a string and an array?

In arduino, a String is a class that is built to hold what we normally think of strings, but it uses dynamic memory allocations which aren't so great on an arduino.

An array of characters (which generally has a NULL byte to signify the end and is then called a string) is a different way to store text, which is a lot more efficient since it only has one byte of overhead (the null)

That depends on what you mean by “string”.

A “C” string:

char *myString = "This is my string";

is an array of characters. It is no different to an “array”.

However, a “C++ String Object” is vastly different.

String myString = "This is my string";

That is an entire object with methods and properties which, while it makes programming easier, is not advised when working with microcontrollers. The memory usage when you’re not doing much with it is only slightly more than a “C” string. However, a lot of the methods involve the allocation and deallocation (freeing) of memory, which leads to memory fragmentation.

“C” strings take a bit more working with, but the benefits from a memory management point of view are worth the time taken to learn about working with them.

A string is a bunch of characters well, um, strung together... the word "string" is a string.

An array is like a set of pigeon holes or mail boxes, where each box could hold a number, a character, or even a string.

But conversely, a string is also a kind of array, since it contains a number of characters, each of which is addressable by dint of its position along the string, in a similar way to each say number in a pigeon hole being addressed by the hole's position.

Have you read this site's pages on Arrays and Strings?

Thankyou everyone for your replies, yes i have read the arduino.cc page on arrays and strings but still am a bit confused. So do they only differ on how they store there data in the arduino?

a string is a array of char's that's null terminated (is what i learned)

An array of char has the nice property that you can treat each member as an individual component. You can do math and comparisons. Many times this is the easiest way to do things. While it may not fit some fancy "Computer Science" idea of how to do things (mixing types...) it works out well for system level work (what C was designed for) and allows you to do many operations with minimal overhead because you don't have to use a lot of routines to convert from one type to another. It can also get you in trouble, but used judiciously and sensibly it is what give C much of its power.

I have done a fair amount of work in Visual Basic - strings have to be examined with special functions Left, Right, Mid, Asc, Chr and such. No such special functions are needed in C and thus less program overhead.

A string (with a lower case s) is an array of characters with a NULL character to mark the end. So if you're talking about string with a lower case s then they're exactly the same thing.

Now those type of strings can be cumbersome for the novice to work with. Sometimes you have to make a lot of code just to do one simple thing with them. One of the C++ programing language's biggest disadvantages is that it isn't very good for handling text.

So some nice fellow came along and wrote the String class. Note the capital S now. Think of it kinda like a library. The String class will contain the same array of characters that you would have used if you had used a (lower case s) string. But in addition to that string of characters, it also contains a bunch of functions to make it real easy to do things with the string. For instance, using the String class I can say "He" + "llo" and it will give me "Hello". With strings (and not knowing about strcat) that would take a few lines of code, you certainly can't just use the + operator like that. That is a function built into the String class.

The trick that the String class uses to do this is called dynamic memory allocation. That means that your array can grow if something is added to it or shrink when something is taken out. With character array's (strings with lower case s) you have to set the size of the array when you declare it and you can't change the size later.

Now if you are programming in C++ on your computer this is a great thing. It makes it super easy to use strings if you can use the String class to hold them. But on a microcontroller like Arduino, you have a very limited amount of RAM memory to work with and not only does the String class take up a bit of memory, but with all that Jostling around and resizing of strings via dynamic memory, the little bit of memory you do have becomes very fragmented meaning all of the available space is there in small blocks of only a few bytes. This causes Arduino to crash. So for Arduino, we tend to stay away from the String class, and work with strings instead.

I think there are a few examples in the posts above about how to declare Strings. That's simple stuff.

To declare a character array (a string) there are two possibilities.

The first is to declare specifically the size of the array. You have to do this if you think the string may grow and you will need more room.

The second is to just declare the name of the array as a pointer (array names are always pointers anyway) and let the compiler figure out how big to make it. Use this method for strings that won't be changing or at least won't ever get any bigger.

This simple program illustrates both.

void setup()
{
  char first_string[17] = "I came first";
  char* second_string = "I was second";
  Serial.begin(9600);
  Serial.println(first_string);
  Serial.println(second_string);
}

void loop()
{  
}

Prints

I came first I was second

first_string is declared as an array of characters to have 17 elements even though only 13 are filled (the 12 characters plus a NULL character at the end). So you could concatenate onto this string four more characters if you wanted, but you would have to use code to find the NULL, do your concatenation, and then add a NULL to the new end (or use strcat and do it in one line but this is what strcat actually does).

The second_string is declared as a pointer to an array of characters and will have only 13 elements (12 letters and a trailing NULL). The compiler sizes it for you since you didn't declare a size, but it still has a set size and you can't change it. You could make it shorter, but you can't make it longer. If you needed to make it longer, you would have to declare a whole new array big enough to hold the addition.

The two different styles are used exactly the same once they are declared. Since first_string is an array name, you can use it (without the square brackets) as a char* (a pointer). Since second_string is declared as a pointer to an array, you can use it (with the square brackets) just like it was an array.

For example I can say

Serial.print(first_string);  // Using first_string without the brackets as a char*
// This will print "I came first"

or

Serial.print(second_string[7]);  // Using the pointer with brackets to access like an array.  
//This will print an 'e' since e is the eighth letter of the string and array index starts at 0.

I think this is where most noobs and some of us old dinosaurs get caught. I spend about 2 hours every morning Wading through a C++ Book and Strings are taught… and Taught and Taught. It does take more than a little reading to understand the idiosyncrasies of the Arduino and some of the apparent omissions in the Arduino that are actually well thought out Commissions… All in ALL the Arduino is Leagues ahead of second best in exposure to a uniform language rather than the Amicus (EX only) people who push a language that must for the most part be unlearned in order to learn C. I can code in basic but so what, what good is it really beyond making some simple projects, I certainly can’t use it with another compiler… Parallax basic… Crowmhills basic, Mikroelectronica, Melabs , CCS in the early days… and the 3 or 4 Free versions. There is very little that is portable there… I decided on the simplistic Arduino realizing what was going to be necessary to learn it and also realizing that at the end of the day I had a head start to C, C++ and Java… just for openers… Remember that I have long ago reached my majority… and today learning becomes harder. Not so much the learning but the ability to pick out the relevant portions from the whole cloth of what I am learning to synthesize an answer to a challenge… This is the difficulty today but I still persevere and I succeed… Slowly… And Enjoy the Hell out of it…

Doc

I just skimmed through. A char array is built into c/c++. The String class is a class defined by the Arduino library. The String class takes up a lot of memory. You can do almost anything with a char array that you can do with the String class.

I have a question: what is the difference between char* and char []? Which one is better, memory-wise and convenience?

I have a question: what is the difference between char* and char ? Which one is better, memory-wise and convenience?

A char * is a pointer. It can only point to memory that has been allocated somewhere. A char array allocates memory, and points to the first element of that array.

One is not better than the other. They are different things. Each has it’s place.

PaulS:

I have a question: what is the difference between char* and char ? Which one is better, memory-wise and convenience?

A char * is a pointer. It can only point to memory that has been allocated somewhere. A char array allocates memory, and points to the first element of that array.

One is not better than the other. They are different things. Each has it’s place.

No, both of those are just un-assigned pointers.

char *x and char x are identical.

It only allocates memory if you place a number in the :

char x[10];

A long time back I got a book called "Assembly Language Step-By-Step" to see how some programmers in a usenet newsgroup I followed were able to write very tight code. Now days I just rely on the easy tools developed by others to get the job done. The side effect of my reading in the book is that often discussions of how programming works takes on the appearance of blind men discribing an elephant. The elephant is the same, but the various discriptions of the elephant by the blind men are interestingly different being biased by their own intepertations. In the area of dynamic memory allocation, I would think a priority would be focusing on cleanup/releasing memory areas after they are used, aka, better use a useful tool.

char *x and char x[] are identical.

They are most certainly NOT.

char x[10];

allocates space for 10 characters. Then,

x[3] = 'D';

is valid.

char *x;

Simply defines a variable that might, or might not, actually be pointed to some memory. It does NOT actually allocate any memory. Therefore,

x[3] = 'B';

is NOT legal. It is not syntactically wrong. It is a logic error, though.

Now,

char *y = x;

does point y to some allocated space. If this is done, then

y[3] = 'G';

is possible.

The critical difference is whether or not the pointer points to allocated memory.

I tried some tests with char*, using .cpp and .c files compiled with MinGW compiler, and run on Windows Command Prompt.
c_datatypes.c compiles perfectly:

#include <stdio.h>
//#include <string.h>
//#include <vector>
main(){
  typedef struct{
    unsigned int id;
    char name[10];
    float salary;
  }employee;
  typedef struct{
    char* name;
    char* number;
    char* address;
  }phoneBook;
  employee daniel;
  phoneBook bell;
  phoneBook *ptrBell = &bell;
  printf("Memory Addresses\nid: %d\nname: %d\nsalary: %d\n\nname: %d\nnumber: %d\naddress: %d\n", &daniel.id, &daniel.name, &daniel.salary, &bell.name, &bell.number, &bell.address);
  ptrBell->name = "Sir";
  ptrBell->number = "905-276-7202";
  ptrBell->address = "456 Uh St.";
  printf("\nValues\nname: %s\nnumber: %s\naddress: %s\n", ptrBell->name, ptrBell->number, ptrBell->address);
}

Output:

C:\MyPrograms>c_datatypes
Memory Addresses
id: 2293512
name: 2293516
salary: 2293528

name: 2293500
number: 2293504
address: 2293508

Values
name: Sir
number: 905-276-7202
address: 456 Uh St.

C:\MyPrograms>

This is the bad string_test.cpp:

#include <iostream>
#include <string.h>
using namespace std;
bool strcmp2(char* str1, char* str2){
  if (strlen(str1) != strlen(str2)) return false;
  else{
    for (int i = 0; i < strlen(str2); i++){
	  if(str1[i] != str2[i]) return false;
	}
  }
  return true;
}
int main(){
  typedef struct{
    char* code;
    char* secretCode;
  }password;
  typedef unsigned char byte;
  password _;
  password *x = &_;
  x->secretCode = "1234";
  char input;
  cout << "Enter password, one character at a time..." << endl;
  while(1){
    for(byte i = 0; i < 4; i++){
      cin >> input;
      x->code[i] = input;
    }
    if(strcmp(x->code,x->secretCode) == 0){
      cout << "Correct!" << endl;
      break;
    }
    else cout << "Wrong Password. Try again..." << endl;
  }
  return 0;
}

Add received this warning:

C:\MyPrograms>c++ string_test.cpp -o string_test.exe
string_test.cpp: In function 'int main()':
string_test.cpp:21:19: warning: deprecated conversion from string constant to 'c
har*' [-Wwrite-strings]

C:\MyPrograms>

Why is the first file legit, and the second file not? I am trying to assign a string to the char* variable.

Assignment ( like you said ) is used in this situation, on globals its initialisation.

Maybe explicit initialisation may help.

password _ = {  (char*)0, "1234" };

also just a nit pick '_' is not a standard valid name. All identifiers beginning with _ in global namespace are supposed to be reserved for current and future internal use.

  x->secretCode = "1234";

x->secretCode is a pointer. It gets an initial value of NULL. You are then trying to store the value "1234" at that NULL pointer.

      x->code[i] = input;

x->code is also a pointer. It gets an initial value of NULL. You are then trying to store the value input in the nth position pointed to by a NULL pointer.

You MUST first allocate space for the pointer to point to. Next, you must make the pointer point to that memory. Only then can you store data in the pointed to location.

Edit: Corrected typo in text.

You are then trying to store the value "1234" at that NULL pointer.

Just to clarify a few things.

"1234";

This is a string literal, its reference is a char*

"1234"[ 2 ] == '3';

This is a valid statement and returns true.

password _ = {  (char*)0, "1234" };

This initialises the structure with the pointer of "1234" as it is placed in global memory it is available throughout the program. ( not global in function scope, but of static nature with global equivalences )

x->secretCode = "1234";

Although this statement is valid, "1234" in this case is a temporary and is not guaranteed to be valid once the statement is complete. However, making a constant reference to the pointer will extend its lifetime to that of the reference, which is functionally equivalent to simply initialising a variable with a value to begin with.

In c_datatypes.c, I did this:

typedef struct{
  char* name;
  char* number;
  char* address;
}phoneBook;
phoneBook bell;
phoneBook *ptrBell = &bell; //isn't this line allocating memory?
//now this is possible:
ptrBell->name = "Sir";
ptrBell->number = "905-276-7202";
ptrBell->address = "456 Uh St.";

and it works.

In string_test.cpp, I basically did the same thing:

typedef struct{
  char* code;
  char* secretCode;
}password;
passsword _;
password *x = &_; //isn't this allocating memory, just like the code above?
x->secretCode = "1234"; //this is the same action as above, but not legit?! 
//...
x->code[i] = input; //by allocating memory, this should be legit

I can change the variable names without any effect. What is the difference? Is it the difference between c and c++?

phoneBook *ptrBell = &bell; //isn't this line allocating memory?

No, it is not allocating memory. It makes ptrBell point to the memory occupied by bell.

ptrBell->name = "Sir";
ptrBell->number = "905-276-7202";
ptrBell->address = "456 Uh St.";

The compiler needs to allocate space for "Sir", etc. So the pointers just point to that space. If the code were in a function, that space would cease to exist when the function ended, resulting in completely different results.

bell::name should be an array, so that you KNOW that there is always space allocated to hold a name, and you should be using strcpy to copy the text there.