Using strtok_s more than once - c++

I am using strtok_s to pull out a value from a C-String based on user input. However, I need to be able to call this function more than one time. Currently when I do it has a problem going through strtok_s. I believe because it is still pointing to a different location and not starting again. ListOfCoeffs is my c-string, which is just a c-string list that has doubles. Degree is the int value that is passed into the function from the user. Is there any way to "reset" strtok so that it will allow me to use this function more than one time without shutting the program down? Apologies for poor style using strtok_s, I am not familiar with it at all.
char * pch;
double coeffValue;
char * context;
pch = strtok_s(listOfCoeffs, " ", &context);
if (degree == 0)
{
// DO NOTHING
}
else
{
for (int i = 0; i < degree; i++)
{
pch = strtok_s(NULL, " ", &context);
}
}
coeffValue = atof(pch);
return coeffValue;

The strtok family of functions destructively modify the input string while tokenizing it. If you want to potentially start over at the beginning, you need to copy the string before passing it to strtok.

Related

Function call resets passed global structs' fields

With reference to the code below: After calling the function CheckSMS and passing the struct * DB1, the fields are updated according the the strtok call. This function reads and parses a text message, storing its contents into char* fields of the DB struct.
In the main loop, I have called Serial.println(DB1.last_order) before and after calling the CheckSMS function. If I have received a text, the order is printed appropriately in the main loop, however on the next call to CheckSMS, DB1.last_order is cleared, replaced with a \n or a NULL or something. I cannot figure out why DB1.last_order does not retain its value, and rather, it is overwritten with every call to CheckSMS. Thanks for any help.
Note - All text messages contain "CMT+", therefore writing to DB1 only happens when a text is received. Calling CheckSMS when no text is received should simply skip through.
int CheckSMS(Robot *DB1) {
int j = 0;
char response[100];
char *pch;
unsigned long previous;
memset(response, '\0', 100);
while(Serial2.available()>0){
response[j] = Serial2.read();
j++;
Serial.println("inc");
}
delay(100);
if (strstr(response, "CMT:") != NULL){
DB1->new_message = strtok(response, " ,");
DB1->last_phone = strtok(NULL, " ,");
pch = strtok(NULL, " ,");
DB1->last_date = strtok(NULL, " ,");
DB1->last_time = strtok(NULL, " ,\n");
DB1->last_order = strtok(NULL," ,\n");
new_message = 1;
}
else{
}
return 0;
}
The strtok function returns pointers to the string you're tokenizing, the local array response in your case. When the function returns the response array goes out of scope and disappears, leaving your structure with pointers to a string that no longer exists, and giving you undefined behavior.
You have a couple of solutions:
Allocate the string dynamically using malloc, but then you must save it in the structure so you can free it when you're done with the structure
Make the response array static, but then the next call to the function will have the same array leading the old data to be updated
Pass in a string to store the response and use that string, the string must have a lifetime at least as long as the structure and don't change contents. The string can of course be a member of the structure itself
The answer Joachim gave is correct, I just want to add that you could also change the Robot structure to contain char arrays (like this: char new_message[MAX_BUF_CHARS]; and so on). Be sure to have enough space in them. Then instead of assigning the pointers returned from strtok, copy the strings in there.

Reverse a string with pointers [duplicate]

This question already has answers here:
C++ Reverse Array
(5 answers)
Closed 7 years ago.
This is an amateur question. I searched for other posts about this topic, found lots of results, but am yet to understand the concepts behind the solution.
This is a practice problem in my C++ book. It is not assigned homework. [Instructions here][1] .
WHAT I WOULD LIKE TO DO:
string input;
getline(cin, input); //Get the user's input.
int front = 0;
int rear;
rear = input.size();
WHAT THE PROBLEM WANTS ME TO DO
string input;
getline(cin, input); //Get the user's input.
int* front = 0;
int* rear;
rear = input.size();
Error: a value of type "size_t" cannot be assigned to an entity of type int*
This makes sense to me, as you cannot assign an 'address' of an int to the value of an int.
So my questions are:
What is the correct way to go about this? Should I just forget about initializing front* or rear* to ints? Just avoid that all together? If so, what would be the syntax of that solution?
Why would this problem want me to use pointers like this? It's clear this is a horrible usage of pointers. Without pointers I could complete this problem in like 30 seconds. It's just really frustrating.
I don't really see an advantage to EVER using pointers aside from doing something like returning an array by using pointers.
Thanks guys. I know you like to help users that help themselves so I did some research about this first. I'm just really irritated with the concept of pointers right now vs. just using the actual variable itself.
Posts about this topic that I've previously read:
[Example 1][2]
[Example 2][3]
[Example 3][4]
[1]: http://i.imgur.com/wlufckg.png "Instructions"
[2]: How does reversing a string with pointers works "Post 1"
[3]: Reverse string with pointers? "Post 2"
[4]: Reverse char string with pointers "Post 3"
string.size() does not return a pointer - it returns size_t.
To revert a string try this instead:
string original = "someText"; // The original string
string reversed = original; // This to make sure that the reversed string has same size as the original string
size_t x = original.size(); // Get the size of the original string
for (size_t i = 0; i < x; i++) // Loop to copy from end of original to start of reversed
{
reversed[i]=original[x-1-i];
}
If you really (for some strange reason) needs pointers try this:
string input;
getline(cin, input); //Get the user's input.
char* front = &input[0];
char* rear = &input[input.size()-1];
but I would not use pointers into a string. No need for it.
I guest you may not quite understand the problem here. This problem want you to COPY a C string then REVERSE it by pointer operation. There is no classes in standard C. So, the C string is quite different from string class in C++. It is actually an array of char-type elements ended with character '\0'.
After understand this, you may start to understand the problem here. If you want to copy a C string, you can not just use str_a = str_b. You need constructor here. However, in pure C style, you should REQUIRE memory space for the string at first (you can use malloc here), then copy each element. For example, you want to create a function to make a copy of input string,
#include <string.h>
char *strcopy(char* str_in) {
int len = strlen(str_in);
char *str_out = (char*)malloc(len+1);
char *in = str_in;
char *out = str_out;
while(*in != '\0') { *out++ = *in++; }
return str_out;
}
As you see, we actually use char* not int* here to operate string element. You should distinguish the pointer (such as in) and the element pointed by the pointer (such as *in) at first.
I'll show you a solution in pure C style for your problem, I hope this would help you to understand it. (You should be able to compile it without modification)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* strreverse(char* in){
// length of input string
int len = strlen(in);
// allocate memory for string operation
char *out = (char*)malloc(len+1);
// initialize <front> and <end>
char *front = out, *end = out + len - 1;
char buffer;
// copy input string
for(int i = 0; i <= len; i++){ out[i] = in[i]; }
// reverse string
for(; front < end; front++, end--) {
buffer = *front;
*front = *end;
*end = buffer;
}
return out;
}
int main() {
printf("REVERSE >> %s\n", strreverse("Hello, World!"));
return 0;
}
This is not you would do by C++ in actual programming, however, I guess the problem here is trying to let you understand mechanism of pointers. In this aspect, original C style would help a lot.

Why does the following code produce a segmentation fault?

I'm trying to execute a UNIX command via my program that will handle up to 4 arguments, why does this either produce a seg fault or other errors?
using namespace std;
int main() {
char buffer[255];
cin >> buffer;
char* firstPtr;
char* secondPtr;
char* thirdPtr;
char* fourthPtr;
firstPtr = strtok(buffer, " ");
secondPtr = strtok(NULL, " ");
thirdPtr = strtok(NULL, " ");
fourthPtr = strtok(NULL, " ");
execlp(firstPtr, secondPtr);
return 0;
}
The crash is because your buffer overflows.
Try to use std::cin.getline(buffer, sizeof(buffer)) instead of std::cin >> buffer
Also note that strtok may return NULL, so be sure you handle it.
I think you should use
char buffer[255];
cin.getline(buffer, 255);
Otherwise your second, third and fourth pointer will be empty.
If you check the man page of execlp, you will notice that the first argument (the second parameter to the method, the arg0 parameter) is mandatory, in addition to any other parameters you might pass to the function via variadic parameters - and it is also mentioned in the text that
The list of arguments must be terminated by a NULL pointer.
The first argument (secondPtr in your case) should be the name of the executable; so you're violating the convention by passing in NULL here (because of the cin >> others have pointed out already).
But in addition, you're also missing at least one more argument at the end which needs to be NULL.
So, a study of man pages is highly recommended!

Assigning chars to a char array with +=

Currently I'm writing a rather extensive homework assignment that - among other things - reads a file, builds a binary search tree and outputs it.
Somewhere inside all that I've written a recursive method to output the values of the binary search tree in order.
void output(node* n)
{
if(n->leftChild != NULL)
output(n->leftChild);
cout << n->keyAndValue << " || ";
outputString += n->keyAndValue << '|';
if(n->rightChild != NULL)
output(n->rightChild);
}
No problem with that, but you'll notice the line outputString += n->keyAndValue << '|';, because I also want to have all the values inside a char array (I am not allowed to use strings or other more current features of C++) that I can use later on in a different method (e.g. Main method).
The Char-Array is declared as follows:
char *outputString;
This being just one of the ways I've tried. I also tried using the const keyword and just regularly building an array char outputString[]. With the version I've shown you I encounter an error when - later on in the program in a different method - calling the following code:
cout << outputString;
I get the following error:
Unhandled exception at 0x008c2c2a in BST.exe: 0xC00000005: Access Violation reading location 0x5000000000.
Any clue as to how I'd be able to build a dynamic char array, assign values to it numerous times using += and outputting it without triggering an access violation? I am sorry for asking a rather basic question but I am entirely new to C++.
Thanks and Regards,
Dennis
I'm guessing that since you can't use std::string, you also can't use new[].
You can concatenate strings with a function like this:
char *concat(const char *s1, const char *s2)
{
size_t len = strlen(s1) + strlen(s2);
char *result = (char*)malloc(len+1);
strcpy(result, s1);
strcat(result, s2);
return result;
}
This can be done more efficiently, but that probably doesn't matter for homework. And you need to check for errors, etc. etc.
You also need to decide who is going to call free on s1 and s2.
For what it is worth, the efficient version looks like this:
char *concat(const char *s1, const char *s2)
{
size_t len1 = strlen(s1);
size_t len2 = strlen(s2);
char *result = (char*)malloc(len1+len2+1);
memcpy(result, s1, len1);
memcpy(result+len1, s2, len2);
result[len1+len2] = '\0';
return result;
}
It's more efficient because it only walks the input strings once.
+= on pointers does pointer arithmetic, not string concatenation. Eventually you get way beyond your array that outputString was pointing to, and trying to print it leads to a segfault.
Since you can't use std::string, you need to use strcat along with new[] and delete[] and make sure you allocated your original array with new[].

Can you change the size of what a pointer point to

For example if a pointer points to an array of chars that read "Hello how are you?" And you only want the pointer to point to Hello. I am passing in a char pointer and when I cout it, it reads the entire array. I try to cut down the size using a for loop that break when it hit a ' '. But I am not having luck figuring it out. Any ideas?
const char *infile(char * file )
{
cout<<file<<endl; //this prints out the entire array
int j;
for(j=0;j<500; j++)
{
if(file[j]==' ')
break;
}
strncpy(file, file, j);
cout<<file<<endl; //how to get this to print out only the first word
}
strncpy() does not append a null terminator if there isn't one in the first j bytes of your source string. And your case, there isn't.
I think what you want to do is manually change the first space to a \0:
for (j = 0; j < 500; j++) {
if (file[j] == ' ') {
file[j] = '\0';
break;
}
}
First, avoid strtok (like the plague that it mostly is). It's unpleasant but sometimes justifiable in C. I've yet to see what I'd call justification for using it in C++ though.
Second, probably the easiest way to handle this (given that you're using C++) is to use a stringstream:
void infile(char const *file)
{
std::strinstream buffer(file);
std::string word;
buffer >> word;
std::cout << word;
}
Another possibility would be to use some of the functions built into std::string:
void infile(char const *file) {
std::string f(file);
std::cout << std::string(f, 0, f.find(" "));
}
...which, now that I think about it, is probably a bit simpler than the stringstream version of things.
A char* pointer actually just points to a single char object. If that object happens to be the first (or any) element of a string, you can use pointer arithmetic to access the other elements of that string -- which is how strings (C-style strings, not C++-style std::string objects) are generally accessed.
A (C-style) string is simply a sequence of characters terminated by a null character ('\0'). (Anything after the '\0' terminator isn't part of the string.) So a string "foo bar" consists of this sequence of characters:
{ 'f', 'o', 'o', ' ', 'b', 'a', 'r', '\0' }
If you want to change the string from "foo bar" to just "foo", one way to do it is simply to replace the space character with a null character:
{ 'f', 'o', 'o', '\0', ... }
The ... is not part of the syntax; it represents characters that are still there ('b', 'a', 'r', '\0'), but are no longer part of the string.
Since you're using C++, you'd probably be much better off using std::string; it's much more powerful and flexible, and frees you from having to worry about terminators, memory allocation, and other details. (Unless the point of this exercise is to learn how C-style strings work, of course.)
Note that this modifies the string pointed to by file, and that change will be visible to the caller. You can avoid that by making a local copy of the string (which requires allocating space for it, and later freeing that space). Again, std::string makes this kind of thing much easier.
Finally, this:
strncpy(file, file, j);
is bad on several levels. Calling strncpy() with an overlapping source and destination like this has undefined behavior; literally anything can happen. And strncpy() doesn't necessarily provide a proper NUL terminator in the destination. In a sense, strncpy() isn't really a string function. You're probably better off pretending it doesn't exist.
See my rant on the topic.
Doing this would be much easier
if(file[j]==' ') {
file[j] = 0;
break;
..
// strncpy(file, file, j);
Using strtok might make your life much easier.
Split up the string with ' ' as a delimiter, then print the first element you get from strtok.
Use 'strtok', see e.g. http://www.cplusplus.com/reference/clibrary/cstring/strtok/
If what you're asking is "can I dynamically resize the memory block pointed to by this pointer" then... not really, no. (You have to create a new block of the desired size, then copy the bytes over, delete the first block, etc.)
If you're trying to just "print the first word" then set the character at the position of the space to 0. Then, when you output the file* pointer you'll just get the first word (everything up to the \0.) (Read null terminated strings for more information on why that works that way.)
But this all depends on how much of what you're doing is an example to demonstrate the problem you're trying to solve. If you're really 'splitting up strings' then you'll at least want to look in to using strtok.
Why not just output each character at a time and then break once you hit a space.
const char *infile(char * file )
{
cout<<file<<endl; //this prints out the entire array
int j;
for(j=0;j<500; j++)
{
if(file[j]==' ')
break;
cout<<file[j];
}
cout<<endl;
}
This has nothing to do with the size of the pointer. A pointer always has the same size for a particular type.
Strtok might be the best solution (this code using strtok will break the string into substring every time is meets a space, an ",", a dot or a "-".
char str[] ="- This, a sample string.";
char * pch;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str," ,.-");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " ,.-");
}
Source : CPP STRTOK
std::copy(file, std::find(file, file+500, ' '),
std::ostream_iterator<char>(std::cout, ""));
If you allocated the space that a char * points to using malloc, you can change the size using realloc.
char * pzFile = malloc(sizeof("Hello how are you?" + 1));
strcpy(pzFile, "Hello how are you?");
realloc(pzFile, 6);
pzFile[6] = '\0';
Note that if you do not set the null pointer, using the string can cause a problem.
If you were just trying to shorten the string, all you had to do is set the null terminator at position 6. The space allocated is larger than needed, but that's OK as long as it's not shorter.
I strongly advise that mostly what you want to do is COPY the string up to the space.
char * pzInput = malloc(sizeof("Hello how are you?" + 1));
strcpy(pzInput, "Hello how are you?");
char * pzBuffer = malloc(BUFFER_SIZE);
char * pzSrc = pzInput;
char * pzDst = pzBuffer;
while (*pzSrc && ' ' != *pzSrc)
*(pzDst++) = *(pzSrc++);
*pzDst = '\0';
This also ends up with pzSrc pointing at the rest of the string for later use!