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!
Related
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...
This question already has answers here:
How can I correctly assign a new string value?
(4 answers)
Closed 5 years ago.
I need to send a value saved in a variable. When trying to pass this in my payload it keeps referencing to the initial value of mydata, which is unsuccessful test.
static uint8_t *mydatapnt;
uint8_t *strdata = "Successfull test";
static uint8_t mydata [] = "Incorrect test";
void send(){
if (LMIC.opmode & OP_TXRXPEND) {
Serial.println(F("OP_TXRXPEND, not sending"));
} else {
// Prepare upstream data transmission at the next possible time.
LMIC_setTxData2(1, mydata, sizeof(mydata)-1, 0);
Serial.println(F("Packet queued"));
/
}
void setup(){
*mydata = mydatapnt;
}
void loop(){
*mydatapnt = strdata;
Serial.println(*mydatapnt + "");
}
What exactly am I doing wrong? I should receive "successfull test".
You can find the full code project here
About strings...
Strings are just pieces of memory where characters are stored (an array of characters). Strings are terminated by a null character.
To copy a string, you must have sufficient memory in the target string. Then you use strcpy to copy the characters. strcpy appends the terminating null character.
The size of a string is determined with strlen. It does not count the terminating null charcter.
In
char *strptr = "my string";
the pointer points to the literal string. A literal string is read-only. Trying to modify it often leads to a segmentation fault or other terminal error. In:
char myString[] = "my string";
The characters of "my string" are copied to the array myString and the compiler makes its size of the length of the initializing string, plus a null character.
To append to a string, you use strcat. Again, the target must have sufficient memory. You either declare a char array with enough memory, like char mystr[100]; or you can allocate memory with malloc, for example:
char *strptr= malloc(strlen(myString)+1);
strcpy(strptr, myString);
If you no longer need the memory you got from malloc, you must return it to the memory allocator:
free(strptr);
Trying to use strptr after having freed the memory will also result in a segmentation fault or in some other undefined behavior.
*mydatapnt = "success in loop";
This does not store pointer to "success in loop" string into mydatapnt, but rather store address of that string into first character of mydatapnt. (At this time mydatapnt is not initialized, so it clobbered some random memory location.)
What you more likely wanted to do is: mydatapnt = "success in loop";
Serial.println(*mydatapnt + "");
You're not concatenating strings, but adding value of first char from mydatapnt to pointer to empty string, which is more like substring operation. This will likely print something, because of the way strings are stored in executable, but definetely not what you wanted it to print.
You can't concatenate strings in C with simple +. Try just Serial.println(mydatapnt).
I have a little problem working with pointers and arrays. The trouble lies on I have a function which creates a new array from the original one, choosing the appropiate characters from a period passed from a parameter. Here is the protype:
char *get_string_period(char chain[], uint8_t period);
I've used a pointer to that array I want to return because I can't return my new array of characters itself. So I save in main.c this pointer into a variable and I do a printf:
char *ptr = get_string_period(chain, period);
printf(“The string of the new array is %s”, ptr);`
But printf shows a short version of my generated array. If I print from the function I get:
vtvfnstrtmwiapjhqsblzgtiapyogiytzhvuswzsfevpsdbljjgmfwoikuvfmoeotwsjwtgussmbegvlxjutktmkzvvvttwlyeqhuwk
From main.c:
vtvfnstrtmwiapjhqsblzgti��j
How can I solve it?
One question more: how can I reuse this array passing it to another function whose parameter is an array itself (char chain[ ])?
Thanks in advance.
Probably get_string_period returns a char pointer to a local variable, so when the function returned, what it actually returned will point to an invalid address.
Instead of outputting some garbage value, sometimes a segmentation fault occurs in situations like this.
A char array is terminated by a null byte. That's how printf statement works. It looks for the null byte to end the char array. if your char * doesn't have null byte, printf will keep printing as long as it can.
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.
I have used this line of code many times (update: when string was a parameter to the function!), however when I try to do it now I get a bus error (both with gcc and clang). I am reproducing the simplest possible code;
char *string = "this is a string";
char *p = string;
p++;
*p='x'; //this line will cause the Bus error
printf("string is %s\n",string);
Why am I unable to change the second character of the string using the p pointer?
You are trying to modify read only memory (where that string literal is stored). You can use a char array instead if you need to modify that memory.
char str[] = "This is a string";
str[0] = 'S'; /* works */
I have used this line of code many times..
I sure hope not. At best you would get a segfault (I say "at best" because attempting to modify readonly memory is unspecified behavior, in which case anything can happen, and a crash is the best thing that can happen).
When you declare a pointer to a string literal it points to read only memory in the data segment (look at the assembly output if you like). Declaring your type as a char[] will copy that literal onto the function's stack, which will in turn allow it to be modified if needed.