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.

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.

Okay, so it is pointing to memory. Why did my first code work properly, and the second code does not execute? What error does the second code have that the first code doesn't? Both of the do the following:

  1. Define a struct full of char*
  2. Create an instance of the struct
  3. Create a pointer to the struct
  4. Assign a string to the char* via pointer

This Arduino test code

#include <MomentaryButton.h>
MomentaryButton button(2);
MomentaryButton nButton(4);
typedef struct{
  char* secretCode;
  char* code;
}password;
password _;
password *x = &_;
x->secretCode = "1234";
byte pos = 0;
boolean locked = true;
byte redLed = 9;
byte greenLed = 10;
void setup(){
  pinMode(redLed, OUTPUT);
  pinMode(greenLed, OUTPUT);
  button.setup();
  nButton.setup();
}
void loop(){
  if(getKey() >= '0' && getKey() <= '9'){
    x->code[pos] = getKey();
    pos++;
  }
  if(pos-1 == strlen(x->secretCode) && strcmp(x->secretCode, x->code) == 0){
    locked = false;
    digitalWrite(greenLed, HIGH);
    digitalWrite(redLed, LOW);
  }
  if(getKey() == '#'){
    locked = true;
    for(byte i = 0; i < strlen(x->code); i++) x->code[i] = '\0';
    digitalWrite(greenLed, LOW);
    digitalWrite(redLed, HIGH);
  }
}
char getKey(){
  button.check();
  nButton.check();
  if(button.wasClicked()){
    int reading = analogRead(A0);
    reading = map(reading, 0, 1023, 0, 7);
    return reading + 48;
  }
  if(nButton.wasClicked()) return '#';
  return 0;
}

gives the error:
sketch_jul09a:9: error: expected constructor, destructor, or type conversion before '->' token