I have been playing around with strings and pointers. I have been testing with a char array and declaring an array of pointer(s) with 1 element pointing to the char array.
I have varied the way I point to the char array's address and tried to call back the content using the pointer.
First, the code is below and displays the results.
char dflt[10] = "1,234";
char *cptra01[1];
char *cptra02[1];
char (*cptra03)[1];
void setup() {
Serial.begin(74880);
cptra01[0] = &dflt[0];
cptra02[0] = dflt;
//cptra03[0] = dflt; :::::> Does not work : incompatible types in assignment of 'char [10]' to 'char [1]'
Serial.println("");
Serial.print("1) dflt via cptra01[0] is : "); Serial.println(cptra01[0]);
Serial.print("2) dflt via *cptra01[0] is : "); Serial.println(*cptra01[0]);
Serial.println("");
Serial.print("3) dflt via cptra02[0] is : "); Serial.println(cptra02[0]);
Serial.print("4) dflt via *cptra02[0] is : "); Serial.println(*cptra02[0]);
}
void loop() {
}
The above results were a bit surprising to me so I thought I'd enquire with the experts.
Pointer cptra01 points to the first element of the string containing the address
Pointer cptra02 points to the whole thing
Pointer cptra03 points to all the elements in the string but I could not get that syntax to work
My expectations vs. actual results are as follows:
Expectation: My pointer points to the first element of the string and is not dereferenced therefore I was expecting the address of that first element which marks the beginning of the string in memory Result: Instead I get the whole "1,234" string
2) Expectation: The dereferenced value of my pointer points to the first element in the string and therefore I am expecting "1" as the result. Result: "1"
3) Expectation: Pointer not dereferenced, I expected the address of the first element. Result: Instead I get the whole "1,234" string
4) Expectation: Pointer to the whole string is dereferenced, I expected to get "1,234". Result: I get "1" instead, the first element in the string
Although through testing I was able to achieve what I wanted to do (ie return the whole string by reference), my understanding is clearly flawed (got 3 out of 4 wrong) and I was wondering if somebody could shed some light on this.
Also note that "Serial.print()" will print the entire char array if you give it a char array pointer (which is why you're printing the entire array instead of just "1"). You can do an int typecast to prevent this and simply print the address the pointer points to.
Yes, indeed, this was actually originally part of an array of pointers (not just one element) and I left it as is. Same for "dflt" which was part of an array of variables. I should have removed the square brackets for clarity's sake as it can confuse people. Hopefully people will not too sidetracked by this.
The same thing is normally written as:
char *cptra01;
Roger that.
You can also rewrite
cptra01[0] = &dflt[0];
as cptra01 = &dflt;
Roger that. I actually read that using the ampersand means the pointer will only return the first character instead of the whole array when dereferenced (assuming I understood correctly). This is mentioned in this document: Source where they state :
Also, to assign the address of an array to a pointer, we do not use the address-of (&) operator since the name of an array (like label) behaves like the address of that array in this context. That's also why you don't use an ampersand when you pass a string variable to scanf()
That is also the reason why I was testing with and without the "&". The square brackets are still unnecessary though.
Also note that "Serial.print()" will print the entire char array if you give it a char array pointer (which is why you're printing the entire array instead of just "1"). You can do an int typecast to prevent this and simply print the address the pointer points to.
I was not aware of that. Thanks for the information. It kind of makes it hard to debug if your code really only returns "1" but the serial.println returns the whole array and you think it is all ok (unless I am reading this incorrectly). I actually want to keep the formatting (comma-delimited) for this one.
The code posted in Reply #5 compiles fine once the "Does not work comment" is made into an actual comment. And, the comment is wrong since it does compile correctly.
Add the he extra parenthesis here:
char (*cptra03);
Is nonsense. But at least it's harmless nonsense as it compiles anyway.
I added the printing using cptra03 here:
char dflt[10] = "1,234";
char *cptra01;
char *cptra02;
char (*cptra03);
void setup() {
Serial.begin(115200);
cptra01 = &dflt[0];
cptra02 = dflt;
cptra03 = dflt; //:::::> Does not work : incompatible types in assignment of 'char [10]' to 'char [1]'
Serial.println("");
Serial.print("1) dflt via cptra01[0] is : "); Serial.println(cptra01);
Serial.print("2) dflt via *cptra01[0] is : "); Serial.println(*cptra01);
Serial.println("");
Serial.print("3) dflt via cptra02[0] is : "); Serial.println(cptra02);
Serial.print("4) dflt via *cptra02[0] is : "); Serial.println(*cptra02);
Serial.println("");
Serial.print("5) dflt via cptra03[0] is : "); Serial.println(cptra03);
Serial.print("6) dflt via *cptra03[0] is : "); Serial.println(*cptra03);
}
void loop() {
}
It runs and produces EXACTLY the result that should be expected:
1) dflt via cptra01[0] is : 1,234
2) dflt via *cptra01[0] is : 1
3) dflt via cptra02[0] is : 1,234
4) dflt via *cptra02[0] is : 1
5) dflt via cptra03[0] is : 1,234
6) dflt via *cptra03[0] is : 1
you can print elements of array, but if you tried printing "array" as an integer, you would get an error because it refers to the starting address of the array in memory.
and print understands the nomenclature for character arrays described with double quotes. So you give print a pointer to a character and it knows it's an arrays of characters terminated with a null without needed to say "*s".
in your example
char dflt[10] = "1,234";
char *cptra01 = dflt;
using cptra01 is equal to using dflt. they both are addresses to string arrays.
"cptr01 [2]" is like any other array, referring to the 3rd element, "2"
but i get a compiler error when I attempt the following.
Serial.println(*cptra02 [0]);
and the following produces ",234" since it specifies the address (&) of the 2nd element in the string
After having a look at the comments and examples, I think my confusion stems from the fact that pointers to say an integer for example and a char array do not seem to behave the same.
I have updated the code adding the example of an integer.
cptra02 (pointer to a char array) vs iptr (pointer to an integer):
cptra02 does not contain an address but the entire content of array dflt which gets printed to serial.
iptr does contain an address and not the value of i. Serial will print the address of i via iptr, not the content of i.
*cptra02 contains the first element of array dflt and serial prints "1".
*iptr is the dereferenced pointer of i and serial prints the value of i, 345.
&cptra02 contains the address of (the first element) of array dflt. Serial prints the address.
&i contains an address as well. Serial prints the address.
So, am I misunderstanding something or pointers to integers and strings / char arrays do not seem to behave the same in terms of the syntax and what each case implies? So in this case, learning about pointers to integers is clouding my understanding of pointers to strings as the syntax does not seem to mean the same thing in one case versus the other (except for &cptra02 and &i).
At first glance that would not seem very logical, but maybe there is some underlying logic that would help to understand why this is the case?
I have updated the code with the integer and other examples:
char dflt[10] = "1,234";
char *cptra01;
char *cptra02;
char (*cptra03); // :::::> Harmless but pointless
int i = 345;
int *iptr;
void setup() {
Serial.begin(74880);
cptra01 = &dflt[0];
cptra02 = dflt;
cptra03 = dflt;
iptr = &i;
Serial.println("");
Serial.print("1) dflt via cptra01 is : "); Serial.println(cptra01);
Serial.print("2) dflt via *cptra01 is : "); Serial.println(*cptra01);
Serial.println("");
Serial.print("3) dflt via cptra02 is : "); Serial.println(cptra02);
Serial.print("4) dflt via *cptra02 is : "); Serial.println(*cptra02);
Serial.println("");
Serial.print("5) dflt via cptra03 is : "); Serial.println(cptra03);
Serial.print("6) dflt via *cptra03 is : "); Serial.println(*cptra03);
Serial.println("");
Serial.print("7a) dflt via &cptra01[1] is : "); Serial.println(&cptra01[1]);
Serial.print("7b) dflt via &cptra02[0] is : "); Serial.println(&cptra02[0]);
Serial.print("7c) dflt via &cptra02 is : "); Serial.println("error: call of overloaded 'println(char**)' is ambiguous");
Serial.print("7d) address of dflt via &cptra02 is : "); Serial.println((unsigned int)&cptra02, HEX);
Serial.print("8) dflt via cptra01[0] is : "); Serial.println(cptra01[0]);
Serial.println("");
Serial.print("9a) i via iptr is : "); Serial.println("error: call of overloaded 'println(int*&)' is ambiguous");
Serial.print("9b) address of i via iptr is : "); Serial.println((unsigned int)iptr, HEX);
Serial.print("10) i via *iptr is : "); Serial.println(*iptr);
Serial.print("11a) i via &i is : "); Serial.println("error: call of overloaded 'println(int*)' is ambiguous");
Serial.print("11b) address of i via &i is : "); Serial.println((unsigned int)&i, HEX);
Serial.println("");
*iptr = 678;
Serial.print("12a) i via iptr is : "); Serial.println("error: call of overloaded 'println(int*&)' is ambiguous");
Serial.print("12b) address of i via iptr is : "); Serial.println((unsigned int)iptr, HEX);
Serial.print("13) i via *iptr is : "); Serial.println(*iptr);
Serial.print("14a) i via &i is : "); Serial.println("error: call of overloaded 'println(int*)' is ambiguous");
Serial.print("14b) address of i via &i is : "); Serial.println((unsigned int)&i, HEX);
}
void loop() {}
All pointers are addresses. Possibly what is confusing you is the behavior of serial.print: it treats a char pointer in a different way to other pointers. It expects a char pointer to point to a C string, I.e. a null terminated array of characters which it knows how to print. If you pass it a pointer to an int, no such special behavior exists.
jg1xmv:
cptra02 does not contain an address but the entire content of array dflt which gets printed to serial.
iptr does contain an address and not the value of i. Serial will print the address of i via iptr, not the content of i.
This is wrong. Clear up that misunderstanding in your mind before going any further. A pointer always contains the address of a memory location.
Thank you everybody for all the comments, this has been really helpful in clarifying things for me.
So thankfully pointers are always addresses and there is some logic in this world and in programming!
My confusion really appears to stem from the special treatment of char arrays by Serial.print. Before you guys confirmed it was handled differently I could not understand why an address to a char array passed to Serial.print would output the content of the char array while the same operation with an integer would pass the actual address of the integer (as expected).
I think it is a finer point of programming with the Arduino IDE and probably not something that is so obvious to beginners like myself. That's why when somebody wrote that the output was exactly as expected I was a bit puzzled as it looked anything but obvious to me why it would behave differently.
So, the good news is that what I learnt about pointers still applies it is just that I have to understand the finer points of the use of Serial.print. So in the case of a char array, if I want to get the address of the array via Serial.print I can't just pass it the pointer like with an integer but the pointer preceded by "&" in order to force the compiler to understand that I am looking for an address.
I have learnt something new. It feels great to go from being puzzled to finally understanding what is going on!
jg1xmv:
My confusion really appears to stem from the special treatment of char arrays by Serial.print. Before you guys confirmed it was handled differently I could not understand why an address to a char array passed to Serial.print would output the content of the char array while the same operation with an integer would pass the actual address of the integer (as expected).
there is the distinction between what the variable represents and what functions do with different types of variables
i think the feature of C++ to have different functions with the same name but having different arguments is part of the confusion.
Serial.print() does different things with different types of argument. It knows what to do with a "char" argument vs a "* char" argument vs an "int" argument.
while Serial.print prints the value passed to it if given a "* int" argument, add array pointer, it knows to print the sequence of chars up to the NULL when passed a "* char" argument.