c++ Array MEMMOVE bug - c++

So, what I want to do is placing a 'p' before all vowels, I'm doing that but because of the memmove, the char array is filled with strange symbols.
#include<conio.h>
#include <cstring>
#include <iostream>
using namespace std;
int main()
{
char s1[256];
cin.get(s1,255);
cin.get();
for(int i=0;i<strlen(s1);i++)
{
if(strchr("aeiou",s1[i])){
memmove(s1+i+1,s1+i,strlen(s1));
// duplicating the vowel so i can replace it
s1[i]='p';
i++;
}
}
cout<<s1;
getch();
return 0;
}
Input : oaie

In your memmove call, you are using the incorrect length:
memmove(s1+i+1,s1+i,strlen(s1));
strlen(s1) is the length of the string starting from the beginning and not including the null terminator. So there are two problems. First, you want the length of the string starting from the current position. Second, you want the length including the null terminator, so that the null terminator gets copied.
The result of these bugs is that if the first character is a vowel then the memove will over-write the null terminator and additional garbage in the buffer will start being processed as if it were part of your string.
Additionally memove will access outside the buffer given certain input and garbage in the buffer.
The solution is to use the correct length, strlen(s1+i), and to include the null terminator:
memmove(s1+i+1,s1+i,strlen(s1+i)+1);
cin.get(s1, 255) does store a null terminator, and in fact you can safely give it the correct buffer size: cin.get(s1, 256).
using std::string you can avoid these sorts of mistakes:
#include <cstring>
#include <string>
#include <iostream>
int main() {
std::string s1;
std::getline(std::cin, s1);
for (int i = 0; i < s1.size(); ++i) {
if (std::strchr("aeiou", s1[i])) {
s1.insert(i, "p");
++i;
}
}
std::cout << s1 << '\n';
}
Note that this doesn't have any fixed buffer size, doesn't have to give special consideration to null terminators, doesn't have to figure out how many bytes need moving, and directly expresses the intent to "insert 'p' at this location".

Related

How to process memory spaces saved in a pointer?

I've saved in a pointer an address of a word saved in a char list. I'm using strtok function to get the words delimited by the keywords I've set.
#include <iostream>
#include <cstring>
#include <cctype>
using namespace std;
int main() {
unsigned int i, z;
char sir[256];
cin.getline(sir, 256);
for(i = 0; i < strlen(sir); ++i){
char * p = strtok(sir, " ,.");
while(p != nullptr) {
// here i want to process the word.
p = strtok(sir, " ,.");
}
}
return 0;
}
What I want to do is to process the words like that:
Let's assume the word "StackOverflow", i want to go from the first letter which is "S" to the last letter which is "w". How can i do that?
Thank you very much, I hope it's clear what I'm asking.
Changed the input to a static value; but just switch that out.
#include <iostream>
#include <cstring>
#include <cctype>
using namespace std;
int main()
{
unsigned int i, z;
char sir[256] = "Thisissome ,.StackOverflow ,.sampletext";
//cin.getline(sir, 256);
char * p = strtok(sir, " ,.");
std::string word("StackOverflow");
do
{
printf ("%s\n",p);
std::string test(p);
if (word.compare(test) == 0)
{
printf("--> Found it!\n");
}
p = strtok (NULL, " ,.-");
} while(p != nullptr);
return 0;
}
strtok splits a string into a series of tokens. It shouldn't be successively called using the original character array to parse based on a delimiter. (i.e. the for(...) strtok(...) in OP).
The initial call expects a c-string for argument; and successful calls expects a nullptr. One each successive call; the next value will be returned from the c-string after the delimiter.
Once a null character is found; the function call will always return nullptr ( when nullptr is the first argument).
Since the solution is already using C++, this solution uses a std::string to show how each sequence of words will appear; and can be compared against a token word.
The value returned to p is still just a char*, so the OP can decide how to use the value returned by strtok. The example is intended to simply show to return delimited words using strtok; and a simple solution for seeing if that word is "StackOverflow"

Issues reverting a char array with C++ via pointers

I am well aware that the instructions for this are highly innefficient/almost obsolete. I actually developed a much simpler solution using strings, but for education purposes, my university has decided to make it a requirement that we solve this issue by the use of pointers and char arrays rather than strings.
Basically, I need to pass a predefined char array (a specific phrase) and have it returned reversed.
So far, my output is absolute gibberish (Some characters which I cannot even type here) so I assume I must be doing something very wrong, but I can't see why.
To experiment, I tried to manually assign the *ptr_cha at the end of the function body to be something like "Hello", but then I'm met with type conversion errors. If I manually assign temp[0] to be "hello", and skip out the for cycle and simply say at the end that *ptr_cha[0] is equal to temp[0], I still get gibberish.
And if I try to output the contents of clone at the start of the function (after saying it's equal to ptr_cha[0]), it says the contents are "d", a letter which is not even present in the original sentence.
This is my whole code:
#include <iostream>
#include <wchar.h>
#include <locale.h>
#include <array>
using namespace std;
void invertChar(char *ptr_cha[]);
int main()
{
setlocale(LC_ALL, "");
char sentence[] {"Pablito clavó un clavito que clavito clavó Pablito"};
char *ptr_sentence[] {nullptr};
*ptr_sentence = sentence;
invertChar(ptr_sentence);
cout << ptr_sentence[0];
};
void invertChar(char *ptr_cha[]) {
char clone[] = {""};
char temp[] = {""};
ptr_cha[0] = clone;
int length = sizeof(clone)/sizeof(*clone);
int j = length;
for(int i = 0; i < length; i++) {
temp[i] = clone[j];
j--;
};
*ptr_cha[0] = temp[0];
};
As mentioned, the idea is for sentence to be set to its inverted form and displayed in the output.
As an additional, side question: Why is calculating the length of a char array in c++ so complicated/verbose? For strings there's a simple method, here you have to do this whole "trick" of dividing the sizeof the array by the sizeof its reference. I don't even see how the storage size of the array divided by the storage size of its pointer could return the length of the array...
Let me break down what's happening in each step. If you're using an IDE I highly recommend you to debug your program and see what's happening in each step. (In your code I assumed that you wanted to reverse 'sentence' and not return a copy of its reversed version.)
wchar.h and array are not used here, you can just delete those lines.
Other than that, you shouldn't pass a character string to a function like that. See this how to do properly.
#include <iostream>
#include <wchar.h> // Not used.
#include <locale.h>
#include <array> // Not used.
using namespace std;
void invertChar(char *ptr_cha[]);
Here, you should just pass sentence to invertChar, ptr_sentence is unnecessary and strange (char* ptr_sentence would be enough because now it's an array that contains pointers to chars and you store the address of sentence in its first slot).
int main()
{
setlocale(LC_ALL, "");
char sentence[] {"Pablito clavó un clavito que clavito clavó Pablito"};
char *ptr_sentence[] {nullptr};
*ptr_sentence = sentence;
invertChar(ptr_sentence);
cout << ptr_sentence[0];
};
void invertChar(char *ptr_cha[]) {
char clone[] = {""};
char temp[] = {""};
You are assigning clone to ptr_cha[0], now ptr_cha[0] is referencing clone and not to sentence. At this point you cannot reach sentence.
ptr_cha[0] = clone;
The first line below would be more descriptive written like this: int length = sizeof(clone) / sizeof(clone[0]). This divides the size of clone with the size of its first element, basically giving you the number of elements clone has. It's important to divide by the element size because what if clone uses something to store characters that isn't 1 byte long like char. You can get the number of elements of any array with this trick.
int length = sizeof(clone)/sizeof(*clone);
int j = length;
for(int i = 0; i < length; i++) {
Remember that both temp and clone are empty strings, more precisely they have 1 element and that's the \0 character that indicates the end of the string.
In the first run of the loop you are doing this: temp[0] = clone[1] but clone doesn't have a second element (index 1). At this point you are accessing something that's out of the array and assigning it to temp where it gets interpreted as a char, resulting in some "gibberish".
temp[i] = clone[j];
j--;
};
*ptr_cha[0] = temp[0];
};
Overall, I would recommend you to look into pointers and how they are working because they can be a little tricky and confusing.
Working C(++) implementation:
#include <iostream> // cout
#include <locale.h> // setlocale
#include <string.h> // strlen
void reverse(char* string)
{
// Check whether our pointer really points to something or not.
if (string == nullptr) return;
// 'strlen' returns the size of a '\0' terminated character sequence (including the '\0').
// We subtract 1 from the length because we don't want to swap the terminating
// '\0' character with the first one.
const int length = strlen(string) - 1;
for (int i = 0, j = length; i < j; ++i, --j) {
const char temp = string[i];
string[i] = string[j];
string[j] = temp;
}
}
int main()
{
setlocale(LC_ALL, "");
char sentence[] = "Pablito clavó un clavito que clavito clavó Pablito";
reverse(sentence);
std::cout << sentence << '\n';
return 0;
}
C++ implementation just for comparison:
#include <algorithm> // reverse
#include <iostream> // cout
#include <locale> // locale, locale::global
#include <string> // string
void reverse(std::string& string)
{
std::reverse(string.begin(), string.end());
}
int main()
{
std::locale::global(std::locale(""));
std::string sentence = "Pablito clavó un clavito que clavito clavó Pablito";
reverse(sentence);
std::cout << sentence << '\n';
return 0;
}

argument list for class template "std::vector" is missing

I am in need of some help with this program. I am in my first ever programming class and have run into wall trying to getting my program to work. I have included what I have written so far but still it doesn't compile. It is giving the error: argument list for class template "std::vector" is missing.
Here is the question:
When you read a long document, there is a good chance that many words occur multiple times. Instead of storing each word, it may be beneficial to only store unique words, and to represent the document as a vector of pointers to the unique words. Write a program that implements this strategy. Read a word at a time from cin. Keep a vector <char *> of words. If the new word is not present in this vector, allocate memory, copy the word into it, and append a pointer to the new memory. If the word is already present, then append a pointer to the existing word.
Below is code snippet:
#include "stdafx.h"
#include <string>
#include <iostream>
using namespace std;
/* Create a vector of char pointers to hold the individual words.
Create a string input to hold the next input through cin. */
int main() {
vector words;
string input;
/* Keep the while loop running using cin as the condition to read an entire document.
This will end when a document has reached its end. */
while (cin >> input) {
/* For every word read as a string, convert the word into a c-string by allocating
a new character array with the proper size and using c_str and strcpy to copy
an identical c-string into the memory heap. */
char* temp = new char[input.length() + 1];
strcpy(temp, input.c_str());
/* Next, check if the word is already in the words array. Use a boolean variable
that updates if the word is found. Compare words by using the strcmp function;
when they are equal, strcmp equals 0. */
bool already_present = false;
for (int i = 0; i < words.size(); i++) {
if (strcmp(temp, words[i]) == 0) {
already_present = true;
}
}
/* If the word is already present, delete the allocated memory.
Otherwise, push the pointer into the words vector. */
if (already_present) {
delete temp;
} else {
words.push_back(temp);
}
}
}
I hope below code snippet could be helpful:
#include <string>
#include <iostream>
#include <string.h> // String.h for strcmp()
#include <vector> // Vector Header file is added
using namespace std;
int main() {
vector <char *> words; // vector of char *
string input;
while (cin >> input) {
char *temp = new char[input.length() + 1];
strcpy(temp, input.c_str());
bool already_present = false;
for (unsigned int i = 0; i < words.size(); i++) {
if (strcmp(temp, words[i]) == 0) {
already_present = true;
}
}
if (already_present) {
delete temp;
} else {
words.push_back(temp);
}
}
/* Print the desired output */
for(unsigned int i=0; i<words.size(); i++) {
cout << words[i] << endl;
}
return 0;
}
Any doubt, comments most welcome.
EDIT: After reading your comments, I came to the conclusion that you use Microsoft Visual Stdio. See, the reason you were getting warning is that strcpy() is potentially unsafe because it can lead to buffer overflow if you try to copy a string to a buffer that is not large enough to contain it.
Consider a code snippet for a moment:
char foo[10]; /* a buffer able to hold 9 chars (plus the null) */
char bar[] = "A string longer than 9 chars";
strcpy( foo, bar ); /* compiles ok, but VERY BAD because you have a buffer overflow
and are corrupting memory. */
strcpy_s() is safer because you have to explicitly specify the size of the target buffer, so the function will not overflow:
strcpy_s( foo, 10, bar ); /* strcpy_s will not write more than 10 characters */
The limitations of this strcpy_s() is that, it is non-standard and MS specific. Therefore if you write code to use it, your code will not be portable any more.

Delete repeated characters from a random word

I'm making a class to delete repeated character from a random word. For example if the input is "aabbccddeeff", it should output "abcdef". However my output contains strange characters after "abcdef". The main.cpp file already exists as the requirements for creating the class. Please see the following codes:
main.ccp
#include <iostream>
#include "repeatdeletion.h"
using namespace std;
int main()
{
char* noRepeats;
int length;
string s;
cout<<"Enter a random word with repeating characters: ";
cin>>s;
RepeatDeletion d;
length=s.length();
noRepeats=d.deleteRepeats(s, length);
cout<<"Your word without any repeating characters: ";
for (int k=0; k<length; k++){
cout<<noRepeats[k];
}
cout<<endl;
delete [] noRepeats;
noRepeats=NULL;
return 0;
}
repeatdeletion.h
#ifndef REPEATDELETION_H
#define REPEATDELETION_H
#include <iostream>
using namespace std;
class RepeatDeletion
{
char* c;
char arr[128]={};
bool repeated;
bool isRepeated(char);
public:
RepeatDeletion();
~RepeatDeletion();
char* deleteRepeats(string, int);
};
#endif // REPEATDELETION_H
repeatdeletion.cpp
#include "repeatdeletion.h"
RepeatDeletion::RepeatDeletion()
{
repeated=false;
}
RepeatDeletion::~RepeatDeletion()
{
delete [] c;
c=NULL;
}
bool RepeatDeletion::isRepeated(char c){
bool repeated=false;
if (arr[c]>=1){
repeated=true;
arr[c]++;
}else{
arr[c]++;
}
return repeated;
}
char* RepeatDeletion::deleteRepeats(string str, int len){
c=new char[len];
int j=0;
for (int i=0; i<len; i++){
if (isRepeated(str[i])==false){
c[j]=str[i];
j++;
}
}
return c;
}
Your return character array is not null terminated.
The length function of string does not include \0.
You have two choices
Add null at the end of returned character array, and std::cout the char array directly (instead of char by char)
Output the final length of your char array, and use that as range to print it char by char
Your printing loop loops using the old and unmodified string length. That means you will go outside the characters you added to memory returned by deleteRepeats.
The easiest solution to handle this is to terminate the data as a proper string, and check for the terminator in the loop.
If you want to use a C-string array, they have a null terminator at the end. That means you'll want to (in deleteRepeats) define your character array one character larger than the length:
c=new char[len+1];
And, after the for loop, ensure you put that null terminator in:
c[j] = '\0';
Then, in your calling function, you can just do:
cout << noRepeats;
Even if you don't want to use C strings, you'll need to communicate the new length back to the caller somehow (currently, you're using the original length). The easiest way to do that is (IMNSHO) still using a C-style string and using strlen to get the new length (a).
Otherwise, you're going to need something like a reference parameter for the new length, populated by the function and used by the caller.
(a) But I'd suggest rethinking the way you do things. If you want to be a C++ coder, be a C++ coder. In other words, use std::string for strings since it avoids the vast majority of problems people seem to have with C strings.
That's because in your code you write the following:
cout<<"Your word without any repeating characters: ";
for (int k=0; k<length; k++){
cout<<noRepeats[k];
}
cout<<endl;
Here, length refers to the length of the original string (which you, by the way shouldn't pass to your deleteRepeats method). I would suggest you make deleteRepeats return a string and write something like this:
std::string noRepeats = d.deleteRepeats(s);
std::cout << "Your word without any repeating characters: ";
std::cout << noRepeats << std::endl;
C-style string (char *, if you insist) follow the convention that the last character is '\0', indicating that the string ends. You could also change deleteRepeats by appending '\0', i.e.
char* RepeatDeletion::deleteRepeats(string str){
c = new char[str.size() + 1];
int j = 0;
for (int i = 0; i < str.size(); i++){
if(isRepeated(str[i]) == false){
c[j] = str[i];
j++;
}
}
c[j] = '\0';
return c;
}
and in your main
std::cout << noRepeats << std::endl;
instead of the for loop. But really, you should use std::string, and if possible not mix it with char *. Hope that helps.
for(k=0;k<length;k++)
Here length should be the exact length of noRepeats, but not of s
so :
char* RepeatDeletion::deleteRepeats(string str, int len)
should return the length-after too
use std::unique it does what you want:
std::string s{};
std::cin>>s;
auto it = std::unique(std::begin(s), std::end(s));
s.resize(std::distance(std::begin(s),it));
std::cout << s;
the way it works is to go through the range begin to end and move all the remaining elements forward if the current element is equal to the next. It returns the position of the end of the new string (it in this example) but does not actually shorten the string so on the next line we shorten the string to the length equal to the distance of begin() to it.
see live at http://ideone.com/0CeaHW

Using strtok with a std::string

I have a string that I would like to tokenize.
But the C strtok() function requires my string to be a char*.
How can I do this simply?
I tried:
token = strtok(str.c_str(), " ");
which fails because it turns it into a const char*, not a char*
#include <iostream>
#include <string>
#include <sstream>
int main(){
std::string myText("some-text-to-tokenize");
std::istringstream iss(myText);
std::string token;
while (std::getline(iss, token, '-'))
{
std::cout << token << std::endl;
}
return 0;
}
Or, as mentioned, use boost for more flexibility.
Duplicate the string, tokenize it, then free it.
char *dup = strdup(str.c_str());
token = strtok(dup, " ");
free(dup);
If boost is available on your system (I think it's standard on most Linux distros these days), it has a Tokenizer class you can use.
If not, then a quick Google turns up a hand-rolled tokenizer for std::string that you can probably just copy and paste. It's very short.
And, if you don't like either of those, then here's a split() function I wrote to make my life easier. It'll break a string into pieces using any of the chars in "delim" as separators. Pieces are appended to the "parts" vector:
void split(const string& str, const string& delim, vector<string>& parts) {
size_t start, end = 0;
while (end < str.size()) {
start = end;
while (start < str.size() && (delim.find(str[start]) != string::npos)) {
start++; // skip initial whitespace
}
end = start;
while (end < str.size() && (delim.find(str[end]) == string::npos)) {
end++; // skip to end of word
}
if (end-start != 0) { // just ignore zero-length strings.
parts.push_back(string(str, start, end-start));
}
}
}
There is a more elegant solution.
With std::string you can use resize() to allocate a suitably large buffer, and &s[0] to get a pointer to the internal buffer.
At this point many fine folks will jump and yell at the screen. But this is the fact. About 2 years ago
the library working group decided (meeting at Lillehammer) that just like for std::vector, std::string should also formally, not just in practice, have a guaranteed contiguous buffer.
The other concern is does strtok() increases the size of the string. The MSDN documentation says:
Each call to strtok modifies strToken by inserting a null character after the token returned by that call.
But this is not correct. Actually the function replaces the first occurrence of a separator character with \0. No change in the size of the string. If we have this string:
one-two---three--four
we will end up with
one\0two\0--three\0-four
So my solution is very simple:
std::string str("some-text-to-split");
char seps[] = "-";
char *token;
token = strtok( &str[0], seps );
while( token != NULL )
{
/* Do your thing */
token = strtok( NULL, seps );
}
Read the discussion on http://www.archivum.info/comp.lang.c++/2008-05/02889/does_std::string_have_something_like_CString::GetBuffer
With C++17 str::string receives data() overload that returns a pointer to modifieable buffer so string can be used in strtok directly without any hacks:
#include <string>
#include <iostream>
#include <cstring>
#include <cstdlib>
int main()
{
::std::string text{"pop dop rop"};
char const * const psz_delimiter{" "};
char * psz_token{::std::strtok(text.data(), psz_delimiter)};
while(nullptr != psz_token)
{
::std::cout << psz_token << ::std::endl;
psz_token = std::strtok(nullptr, psz_delimiter);
}
return EXIT_SUCCESS;
}
output
pop
dop
rop
EDIT: usage of const cast is only used to demonstrate the effect of strtok() when applied to a pointer returned by string::c_str().
You should not use
strtok() since it modifies the tokenized string which may lead to undesired, if not undefined, behaviour as the C string "belongs" to the string instance.
#include <string>
#include <iostream>
int main(int ac, char **av)
{
std::string theString("hello world");
std::cout << theString << " - " << theString.size() << std::endl;
//--- this cast *only* to illustrate the effect of strtok() on std::string
char *token = strtok(const_cast<char *>(theString.c_str()), " ");
std::cout << theString << " - " << theString.size() << std::endl;
return 0;
}
After the call to strtok(), the space was "removed" from the string, or turned down to a non-printable character, but the length remains unchanged.
>./a.out
hello world - 11
helloworld - 11
Therefore you have to resort to native mechanism, duplication of the string or an third party library as previously mentioned.
I suppose the language is C, or C++...
strtok, IIRC, replace separators with \0. That's what it cannot use a const string.
To workaround that "quickly", if the string isn't huge, you can just strdup() it. Which is wise if you need to keep the string unaltered (what the const suggest...).
On the other hand, you might want to use another tokenizer, perhaps hand rolled, less violent on the given argument.
Assuming that by "string" you're talking about std::string in C++, you might have a look at the Tokenizer package in Boost.
First off I would say use boost tokenizer.
Alternatively if your data is space separated then the string stream library is very useful.
But both the above have already been covered.
So as a third C-Like alternative I propose copying the std::string into a buffer for modification.
std::string data("The data I want to tokenize");
// Create a buffer of the correct length:
std::vector<char> buffer(data.size()+1);
// copy the string into the buffer
strcpy(&buffer[0],data.c_str());
// Tokenize
strtok(&buffer[0]," ");
If you don't mind open source, you could use the subbuffer and subparser classes from https://github.com/EdgeCast/json_parser. The original string is left intact, there is no allocation and no copying of data. I have not compiled the following so there may be errors.
std::string input_string("hello world");
subbuffer input(input_string);
subparser flds(input, ' ', subparser::SKIP_EMPTY);
while (!flds.empty())
{
subbuffer fld = flds.next();
// do something with fld
}
// or if you know it is only two fields
subbuffer fld1 = input.before(' ');
subbuffer fld2 = input.sub(fld1.length() + 1).ltrim(' ');
Typecasting to (char*) got it working for me!
token = strtok((char *)str.c_str(), " ");
Chris's answer is probably fine when using std::string; however in case you want to use std::basic_string<char16_t>, std::getline can't be used. Here is a possible other implementation:
template <class CharT> bool tokenizestring(const std::basic_string<CharT> &input, CharT separator, typename std::basic_string<CharT>::size_type &pos, std::basic_string<CharT> &token) {
if (pos >= input.length()) {
// if input is empty, or ends with a separator, return an empty token when the end has been reached (and return an out-of-bound position so subsequent call won't do it again)
if ((pos == 0) || ((pos > 0) && (pos == input.length()) && (input[pos-1] == separator))) {
token.clear();
pos=input.length()+1;
return true;
}
return false;
}
typename std::basic_string<CharT>::size_type separatorPos=input.find(separator, pos);
if (separatorPos == std::basic_string<CharT>::npos) {
token=input.substr(pos, input.length()-pos);
pos=input.length();
} else {
token=input.substr(pos, separatorPos-pos);
pos=separatorPos+1;
}
return true;
}
Then use it like this:
std::basic_string<char16_t> s;
std::basic_string<char16_t> token;
std::basic_string<char16_t>::size_type tokenPos=0;
while (tokenizestring(s, (char16_t)' ', tokenPos, token)) {
...
}
It fails because str.c_str() returns constant string but char * strtok (char * str, const char * delimiters ) requires volatile string. So you need to use *const_cast< char > inorder to make it voletile.
I am giving you a complete but small program to tokenize the string using C strtok() function.
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
int main() {
string s="20#6 5, 3";
// strtok requires volatile string as it modifies the supplied string in order to tokenize it
char *str=const_cast< char *>(s.c_str());
char *tok;
tok=strtok(str, "#, " );
int arr[4], i=0;
while(tok!=NULL){
arr[i++]=stoi(tok);
tok=strtok(NULL, "#, " );
}
for(int i=0; i<4; i++) cout<<arr[i]<<endl;
return 0;
}
NOTE: strtok may not be suitable in all situation as the string passed to function gets modified by being broken into smaller strings. Pls., ref to get better understanding of strtok functionality.
How strtok works
Added few print statement to better understand the changes happning to string in each call to strtok and how it returns token.
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
int main() {
string s="20#6 5, 3";
char *str=const_cast< char *>(s.c_str());
char *tok;
cout<<"string: "<<s<<endl;
tok=strtok(str, "#, " );
cout<<"String: "<<s<<"\tToken: "<<tok<<endl;
while(tok!=NULL){
tok=strtok(NULL, "#, " );
cout<<"String: "<<s<<"\t\tToken: "<<tok<<endl;
}
return 0;
}
Output:
string: 20#6 5, 3
String: 206 5, 3 Token: 20
String: 2065, 3 Token: 6
String: 2065 3 Token: 5
String: 2065 3 Token: 3
String: 2065 3 Token:
strtok iterate over the string first call find the non delemetor character (2 in this case) and marked it as token start then continues scan for a delimeter and replace it with null charater (# gets replaced in actual string) and return start which points to token start character( i.e., it return token 20 which is terminated by null). In subsequent call it start scaning from the next character and returns token if found else null. subsecuntly it returns token 6, 5, 3.