I am finding myself again confused by C strings, chars, etc.
Here is some code I am using to test the syntax on the Arduino. I know that (*message)buff will give me a pointer (I still don’t really know why I need to use pointers, but I can do some research on that!), I convert the *message_buff to a String (just for something to do, but note that later on when I try and print this string to serial I only get a single 'c' character).
I set an array pointer three elements long (three bytes long?? I don't really know):
char *mqtt_command[3] = {};
And later on when I try and add a value to the array using:
*mqtt_command[i] = str;
I get the error:
error: invalid conversion from 'char*' to 'char'
If I change that to:
mqtt_command[i] = str;
(without the *) it compiles fine. I don't know why...
Here is my code:
char *message_buff = "command:range:1";
char *str;
String msgString = String(*message_buff);
char *mqtt_command[3] = {};
int i = 0;
void setup()
{
Serial.begin(9600);
delay(500);
while ((str = strtok_r(message_buff, ":", &message_buff)) != NULL)
{
Serial.println(str);
mqtt_command[i] = str;
i++;
}
delay(1000);
Serial.print("Command: ");
Serial.println(mqtt_command[1]);
Serial.print("MQTT string: ");
Serial.println(msgString);
}
void loop()
{
// Do something here later
}
And here is the output:
command
range
1
Command: range
MQTT string: c
How can I understand chars, strings, pointers, and char arrays? Where can I go for a good all round tutorial on the topic?
I am passing in a command string (I think it is a string, maybe it is a char array????) via MQTT, and the message is:
command:range:1
I am trying to build a little protocol to do things on the Arduino when an MQTT message is received. I can handle the MQTT callbacks fine, that not the problem. The issue is that I don't really understand C strings and chars. I would like to be able to handle commands like:
command:range:0
command:digital:8
read:sensor:2
etc.
You need a C (and/or C++) primer first, you need to work more on your understanding of the declarations and the syntax for pointer access and so on.
This:
char *mqtt_command[3] = {};
means "mqtt_command is an array of 3 char *", i.e. three pointers to characters. Since strings are represented as pointers to characters, this can be called "an array of three strings". There's no actual space for the characters themselves though, so this is not enough to work with but it's a good start.
Then, your first error is this code:
*mqtt_command[i] = str;
The problem the compiler is complaining about is that you're dereferencing things too many times. Just mqtt_command[i] is enough, that evaluates to the i:th value of the array, which has type char *. Then, your initial asterisk dereferences that pointer, meaning the type of the left-hand expression is now char, i.e. it's a single character. You can't assign a pointer into a character, it (typically) won't fit.
Drop the initial asterisk to solve this.
To analyze further, this:
char *message_buff = "command:range:1";
String msgString = String(*message_buff);
is also wrong, for the same reason. You're dereferencing the message_buff pointer, so the argument to the String() constructor is merely the first character, i.e. c. Again, drop the initial asterisk, you mean:
String msgString = String(message_buf);
which can be written as just:
String msgString(message_buf);
mqtt_command[i] = str;
This will work, as mqtt_command[i] is already char pointer. * will redirect it to any previously allocated memory, which is not done in the code.
Related
I am trying to use the C's strtok function in order to process a char* and print it in a display, and looks like that for some reason I don't know the character '\n' is not substituted by '\0' as I believe strtok does. The code is as follows:
-Declaration of char* and pass to the function where it will be processed:
char *string_to_write = "Some text\nSome other text\nNewtext";
malloc(sizeof string_to_write);
screen_write(string_to_write,ALIGN_LEFT_TOP,I2C0);
-Processing of char* in function:
void screen_write(char *string_to_write,short alignment,short I2C)
{
char *stw;
stw = string_to_write;
char* text_to_send;
text_to_send=strtok(stw,"\n");
while(text_to_send != NULL)
{
write_text(text_to_send,I2C);
text_to_send=strtok(NULL, "\n");
}
}
When applying the code, the result can be seen in imgur (Sorry, I am having problems with format adding the image here in the post), where it can be seen that the \n is not substituted as it is the strange character appearing in the image, and the debugger still showed the character as well. Any hints of where can the problem be?
Thanks for your help,
Javier
strtok expects to be able to mutate the string you pass it: instead of allocating new memory for each token, it puts \0 characters into the string at token boundaries, then returns a series of pointers into that string.
But in this case, your string is immutable: it's a constant stored in your program, and can't be changed. So strtok is doing its best: it's returning indices into the string for each token's starting point, but it can't insert the \0s to mark the ends. Your device can't handle \ns in the way you'd expect, so it displays them with that error character instead. (Which is presumably why you're using this code in the first place.)
The key is to pass in only mutable strings. To define a mutable string with a literal value, you need char my_string[] = "..."; rather than char* my_string = "...". In the latter case, it just gives you a pointer to some constant memory; in the former case, it actually makes an array for you to use. Alternately, you can use strlen to find out how long the string is, malloc some memory for it, then strcpy it over.
P.S. I'm concerned by your malloc: you're not saving the memory it gives you anywhere, and you're not doing anything with it. Be sure you know what you're doing before working with dynamic memory allocation! C is not friendly about that, and it's easy to start leaking without realizing it.
1.
malloc(sizeof string_to_write); - it allocates the sizeof(char *) bytes not as many bytes as your string needs. You also do not assign the allocated block to anything
2.
char *string_to_write = "Some text\nSome other text\nNewtext";
char *ptr;
ptr = malloc(strlen(string_to_write) + 1);
strcpy(ptr, string_to_write);
screen_write(ptr,ALIGN_LEFT_TOP,I2C0);
I am trying to test something and I made a small test file to do so. The code is:
void main(){
int i = 0;
char array1 [3];
array1[0] = 'a';
array1[1] = 'b';
array1[2] = 'c';
printf("%s", array1[i+1]);
printf("%d", i);
}
I receive a segmentation error when I compile and try to run. Please let me know what my issue is.
Please let me know what my issue is. ? firstly char array1[3]; is not null terminated as there is no enough space to put '\0' at the end of array1. To avoid this undefined behavior increase the size of array1.
Secondly, array1[i+1] is a single char not string, so use %c instead of %s as
printf("%c", array1[i+1]);
I suggest you get yourself a good book/video series on C. It's not a language that's fun to pick up out of the blue.
Regardless, your problem here is that you haven't formed a correct string. In C, a string is a pointer to the start of a contiguous region of memory that happens to be filled with characters. There is no data whatsoever stored about it's size or any other characteristics. Only where it starts and what it is. Therefore you must provide information as to when the string ends explicitly. This is done by having the very last character in a string be set to the so called null character (in C represented by the escape sequence '\0'.
This implies that any string must be one character longer than the content you want it to hold. You should also never be setting up a string manually like this. Use a library function like strlcpy to do it. It will automatically add in a null character, even if your array is too small (by truncating the string). Alternatively you can statically create a literal string like this:
char array[] = "abc";
It will automatically be null terminated and be of size 4.
Strings need to have a NUL terminator, and you don't have one, nor is there room for one.
The solution is to add one more character:
char array1[4];
// ...
array1[3] = 0;
Also you're asking to print a string but supplying a character instead. You need to supply the whole buffer:
printf("%s", array1);
Then you're fine.
Spend the time to learn about how C strings work, in particular about the requirement for the terminator, as buffer overflow bugs are no joke.
When printf sees a "%s" specifier in the formatting string, it expects a char* as the corresponding argument, but you passed a char value of the array1[i+1] expression. That char got promoted to int but that is still incompatible with char *, And even if it was it has no chance to be a valid pointer to any meaningful character string...
Note: I can't use any libs or includes!
I have the following Code:
void twstng(char * str, int end, int strt) {
if(strt != end && strt != end-1) {
int hlp = str[strt];
printf("strt %d end %d hlp %d\n", strt, end, hlp);
str[strt] = str[end-1];
printf("test\n");
str[end-1] = hlp;
printf("test\n");
twstng(str, strt+1, end-1);
}
}
and in the main function:
char * sol = "hello";
twisting(sol, 5, 0);
I want to twist the entire string. But the console shows:
strt 0 end 4 help 104
And then comes a memory access error. But why?
My second problem is, that in the original task the given string is a
const char * const str
How can I work with it in the twstng function?
Your char *sol is a pointer to the string "hello". Being a string literal, it is actually read-only, and thus when you pass the pointer to your function, you get an error when you modify the contents of the constant string "hello" through the pointer.
Regarding the second part of the question, const char * const (i.e., constant pointer to a constant char) would indeed be a better type for the pointer, as it would convey that the thing pointed to is constant. However, then you cannot pass this pointer to the function (because the function takes a pointer to a non-const char), and it is not clear from the information given how you are "allowed" to work around this. One way is to copy the string and modify the copy.
edit: And as pointed out by other answers, your recursive call mixes up the start and end arguments (by using the more logical order of start first).
In C all string literals are read-only arrays of characters. It can be stored in memory that is not modifiable, leading to errors such as your when you attempt to modify it. That's why you should always use const char * when referring to string literals.
Use an array instead:
char sol[] = "hello";
I believe the recursive call to 'twstng()' at the bottom of the function has passed the new start and end indexes in the wrong order, given the names in the declaration (or else the declaration has them in the wrong order).
You mixed up your arguments.
Your function declaration says, that the first argument is the end and the second is the strt.
Your recursive call mixes them up.
I'm writing a parser in C, and I've got some code that looks like this:
char *consume_while(parser *self, int(*test)(char)) {
char *result;
while (eof(self) && (*test)(next_char(self))) {
// append the return value from the function consumed_char(self)
// onto the "result" string defined above.
}
return result;
}
But I'm kinda new to the whole string manipulation aspect of C, so how would I append the character returned from the function consumed_char(self) to the result char pointer? I've seen people using the strcat function, but that wont work as it takes two constant char pointers, but I'm dealing with a char* and a char. In java it would be something like this:
result += consumed_char(self);
What's the equivalent in C?
Thanks :)
In C, strings do not exist as a type, they are just char arrays with a null-terminating character. This means, assuming your buffers are big enough and filled with zeroes, it can be as simple as:
result[(strlen(result)] = consumed_char(self);
if not, your best bet is to use strcat and change your consumed_self function to return a char *.
That being said, writing a parser without basic understanding of C-style strings, is, to say the least, quite ambitious.
hey guys I need your help. I'm trying to extract a character from a string and set it as the 2nd element of an array of strings. Yet as usual C is giving me segmentation faults, Ive tried sprintf, strcpy, and still segmentation fault the code is:
int getwords(char *line, char *words[])
{
int nwords=2;
char *result= NULL;
char TABS[]="\t";
char spaces[]=" ";
char commas[]=",";
result = strtok(line,TABS);
words[1]=result[strlen(result)-1];//setting the 2nd element of the array to a char
result[strlen(result)-1]='\0';//removing the extracted char from the string
words[0]=result;//setting 1st element to the new modified word
printf("the opcode is:%s and the type is:%c\n",words[0],result[strlen(result)-1]);
return nwords;
}
e.g. If I give it "bye." it should return 2 and an array having 2 elements: 1st elem="bye" 2nd elem="."
I ran some tests and found out that the error is from the statement:
words[1]=result[strlen(result)-1];
Any help is welcom
Are you sure words is a modifiable string?
Literal strings are unmodifiable strings. For example: this gives segmentation fault:
char *test = "forty two";
test[6] = 'T'; /* make two uppercase */
You need to show how you call getwords and the definitions of the variables involved.
I'm guessing you're passing pointers to string literals.
There are two, perhaps four mistakes in the code below, I explain two of the mistakes in the code comments:
If we assume that "line", for the purposes of explaining what happens, is "hey\tthere"...
We also assume that "words" is an array of two pointers to char.
// Find the first token, in this case "hey", and return it in "result".
result = strtok(line,TABS); // NOTE: 'line' has been modified by the function!
// Take the last character in the returned statement, which is 'y', and
// copy it to the second cell in the 'words' array, however we are supposed
// to be copying a *pointer* to char there...
words[1]=result[strlen(result)-1];
Additionally, if "line" is static and can not be changed, the first line above will crash.
If "words" is not allocated or doesn't reference an array of at least two pointers to char, then the second line will crash.
If code execution gets past this point, any code that uses the "words" array will crash because the code will expect pointers, but is getting chars!