Related
To summarize, if the function is given arguments char *str1 = "Watch out the streets?";
char *str2 = "street?";, it should return a pointer in str1 to the first instance of "street", starting from s.
I am completely stuck and appreciate any help. I have a feeling my problem is with pointers. I'm a beginner as you might imagine.
I just edited the code to my latest attempt. I am very close, but cannot still find the idea to modify the first string.
Output image:
const char *qstr_strstr(const char *str1, const char *str2) {
int j = 0;
char newstr2[256];
while (str2[j]) {
if (str2[j] == '?') {
break;
} else {
newstr2[j] = str2[j];
}
j++;
}
newstr2[j] = '\0';
size_t n = strlen(newstr2);
while(*str1) {
if (!memcmp(str1++, newstr2, n)) {
return (str1 - 1);
}
}
return NULL;
}
You are heading in the right direction, and you are starting to think about stepping through stings correctly, but you are getting wrapped up in your use of any additional string -- there is no need for that.
When you are analyzing stings and substrings, all you care about is:
the index (position) within the original string (to iterate);
whether you have found the beginning of the substring yet (if so set flag indicating in word matching chars); and
whether you make it all the way to the end of the substring while your flag is set (if you do, you have found your substring). Otherwise, if there is a mismatch in characters before reaching the end, unset your flag and keep going. Repeat until you run out of str1.
Complicating your case here is the Red-Herring '?' character. You can either use it as a test for end-of-substring, or ignore it altogether. Your goal is to locate str2 "street" within str1 "... streets?". You would generally use ispunct() from ctype.h to identify '?' as a non-word character and not part of the string anyway. Here, you can simply check for '?' in a similar way that you would check for '\0' to mark end-of-string.
Putting it altogether and not using any of the string.h or ctype.h functions, you could do:
#include <stdio.h>
const char *qstr_strstr (const char *str1, const char *str2)
{
int i = 0, instr2 = 0, ndx = 0; /* str1 index, in-str2 flag, str2 index */
if (str1 == NULL || str2 == NULL) /* validte both str1 and str2 not NULL */
return NULL;
do { /* loop over each char in str1 */
/* if in str2 and (at end or at '?') */
if (instr2 && (!str2[ndx] || str2[ndx] == '?'))
return &str1[i-ndx]; /* return address in str1 to start of str2 */
/* if char in str1 and str2 equal */
if (str1[i] == str2[ndx]) {
ndx += 1; /* increment str2 index */
instr2 = 1; /* set in-str2 flag true (done each time) */
}
else /* otherwise chars not equal */
ndx = instr2 = 0; /* reset str2 index, set in-str2 flag false */
} while (str1[i++]); /* includes \0, allows match at end of both */
return NULL;
}
int main (void) {
const char *str1 = "Watch of the streets?",
*str2 = "street?",
*ptr = qstr_strstr (str1, str2);
if (ptr) {
size_t i = ptr - str1;
printf ("ptr : %s\nptr addr : %p\n---\n"
"&str1[%zu] : %s\n&str1[%zu] : %p\n",
ptr, (void*)ptr, i, str1 + i, i, (void*)(str1 + i));
}
}
Example Use/Output
Outputting the string and adderss retuned by qstr_strstr() as well as the address of that string and address located within the original str1 you would have:
$ ./bin/strstrawk
ptr : streets?
ptr addr : 0x4006c1
---
&str1[13] : streets?
&str1[13] : 0x4006c1
You can further copy just the substring street from the address in str1 or whatever else you need to do. Look things over and let me know if you have further questions.
Edit Based On Picture Added
If you want to output just the characters before the '?' from the pointer returned by qstr_strstr(), then you can do that trivially by using the precision modifier with the "%s" output conversion specifier in your printf format string and limit the number of characters output to just the number before the '?' in str2. Your format conversion specifier would look like "%.*s" where it expects 2 arguments, the first of type int being the number of characters, and the second the string.
In the case above the arguments would be:
(int)strcspn (str2, "?"), ptr
Where strcspn() returns the number of characters before the '?' in str2 (cast to int) and ptr the return from qstr_strstr(). Changing the code above you would have:
...
#include <string.h>
...
printf ("ptr : %.*s\nptr addr : %p\n---\n"
"&str1[%zu] : %s\n&str1[%zu] : %p\n",
(int)strcspn (str2, "?"), ptr, (void*)ptr,
i, str1 + i, i, (void*)(str1 + i));
(the remaining code is unchanged)
$ ./bin/strstrawk
ptr : street
ptr addr : 0x4006c1
---
&str1[13] : streets?
&str1[13] : 0x4006c1
Where the output using ptr as the string and the length from str2 is not "street".
Let me know if you have further questions.
I want to get the rest of the string after the first "/" symbol.
The expectation I wanna get is:
index/homepage/component.html/sdfsdf
int main(int argc, char *argv[]){
char link[] = "www.google.com/index/homepage/component.html/sdfsdf";
char *token;
char *temp[1000];
int i=0;
token = strtok(link, "/");
while(token != NULL){
temp[i] = token;
token = strtok(NULL, "/");
++i;
}
printf("the parse string: %s\n",*temp);
return 0;
}
the parse string: www.google.com
The other answers have covered a more prefered method, that is strchr(), but for compleatness this is how it can be done using regular expressions and sscanf.
this works by grabing everything befor the '/' and ignoring it by using %*[^/] (the * means it will not put it into a variable), then on the other side of '/' just getting everything till the end of line char is hit by %[^\n]
#include <stdio.h>
char link[] = "www.google.com/index/homepage/component.html/sdfsdf";
int main(int argc, char **argv){
char buff[128];
// Seporate string after first "/"
// %*[^/] goes untill it finds '/' and stops, but wont put it in a var
// "/" will eat the '/' charater
// %[^\n] goes untill it finds the '\n' char and puts it into buff
sscanf(link, "%*[^/]/%[^\n]", buff);
printf("%s\n", buff);
}
edit: added clarification of the '*'
Since you have one target character you are after in a longer string, to find the first occurrence, you can simply use strchr to return a pointer to the desired character within the larger string. In this case the first '/'. To use strchr to locate the pointer associated with the first '/' your call would simply be:
char *p = strchr (link, '/');
If p is not NULL then it has been found within the string. Recall, the character found was a separator character that was not wanted, so you advance the pointer by 1 so that it is pointing to the first character after the '/'.
A simple call to strlen() at that point will tell you how many characters you must copy from link to your string where you are saving the results. Then using the length, you can simply call memcpy to copy from link beginning at the pointer location to the end of the string (including the nul-terminating character) to obtain the wanted characters. A short example would be:
#include <stdio.h>
#include <string.h>
#define MAXTOK 2048
int main (void) {
char link[] = "www.google.com/index/homepage/component.html/sdfsdf",
*p = link,
token[MAXTOK]; /* declare array to hold results */
if ((p = strchr (link, '/'))) { /* check whether '/' found in line */
size_t len = strlen (++p); /* advance pointer by 1, get length */
if (len > MAXTOK - 1) { /* check if length exceeds available */
fputs ("error: string exceeds allowable length.\n", stderr);
return 1;
}
memcpy (token, p, len + 1); /* copy remaining part of string */
printf ("%s\n", token); /* output it */
}
}
EXample Use/Output
$ ./bin/charstr_rest
index/homepage/component.html/sdfsdf
Providing the desired result string. Look things over and let me know if you have questions.
Hope this Helps..First find out the Position of '/' Character in the String then build your Substring,have mentioned on each block of code Whats it does...
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char link[] = "www.google.com/index/homepage/component.html/sdfsdf";
char linktemp[50];
int i=0,c=0;
////Finding the Position of First '/'
for(i=0;i<strlen(link);i++)
{
if(link[i]=='/')
{
break;
}
}
//If no '/' Character found
if(i==strlen(link))
{
printf("No '/' Character found in the String");
return 0;
}
////Creating the Substring
while(c<strlen(link)-i)
{
linktemp[c]=link[i+c+1];
c++;
}
linktemp[c] ='\0';
printf("the parse string: %s\n",linktemp);
return 0;
}
I am writing my own trim() in C. There is a structure which contains all string values, the structure is getting populated from the data coming from a file which contains spaces before and after the beginning of a word.
char *trim(char *string)
{
int stPos,endPos;
int len=strlen(string);
for(stPos=0;stPos<len && string[stPos]==' ';++stPos);
for(endPos=len-1;endPos>=0 && string[endPos]==' ';--endPos);
char *trimmedStr = (char*)malloc(len*sizeof(char));
strncpy(trimmedStr,string+stPos,endPos+1);
return trimmedStr;
}
int main()
{
char string1[]=" a sdf ie ";
char *string =trim(string1);
printf("%s",string);
return 0;
}
Above code is working fine, but i don't want to declare new variable that stores the trimmed word. As the structure contains around 100 variables.
Is there any way to do somthing like below where I dont need any second variable to print the trimmed string.
printf("%s",trim(string1));
I believe above print can create dangling pointer situation.
Also, is there any way where I don't have to charge original string as well, like if I print trim(string) it will print trimmed string and when i print only string, it will print original string
elcuco was faster. but it's done so here we go:
char *trim(char *string)
{
char *ptr = NULL;
while (*string == ' ') string++; // chomp away space at the start
ptr = string + strlen(string) - 1; // jump to the last char (-1 because '\0')
while (*ptr == ' '){ *ptr = '\0' ; ptr--; } ; // overwrite with end of string
return string; // return pointer to the modified start
}
If you don't want to alter the original string I'd write a special print instead:
void trim_print(char *string)
{
char *ptr = NULL;
while (*string == ' ') string++; // chomp away space at the start
ptr = string + strlen(string) - 1; // jump to the last char (-1 because '\0')
while (*ptr == ' '){ ptr--; } ; // find end of string
while (string <= ptr) { putchar(*string++); } // you get the picture
}
something like that.
You could the original string in order to do this. For trimming the prefix I just advance the pointer, and for the suffix, I actually add \0. If you want to keep the original starting as is, you will have to move memory (which makes this an O(n^2) time complexity solution, from an O(n) I provided).
#include <stdio.h>
char *trim(char *string)
{
// trim prefix
while ((*string) == ' ' ) {
string ++;
}
// find end of original string
char *c = string;
while (*c) {
c ++;
}
c--;
// trim suffix
while ((*c) == ' ' ) {
*c = '\0';
c--;
}
return string;
}
int main()
{
char string1[] = " abcdefg abcdf ";
char *string = trim(string1);
printf("String is [%s]\n",string);
return 0;
}
(re-thinking... is it really O(n^2)? Or is it O(2n) which is a higher O(n)...? I guess depending on implementation)
You can modify the function by giving the output in the same input string
void trim(char *string)
{
int i;
int stPos,endPos;
int len=strlen(string);
for(stPos=0;stPos<len && string[stPos]==' ';++stPos);
for(endPos=len-1;endPos>=0 && string[endPos]==' ';--endPos);
for (i=0; i<=(endPos-stPos); i++)
{
string[i] = string[i+stPos];
}
string[i] = '\0'; // terminate the string and discard the remaining spaces.
}
...is there any way where i don't have to charge original string as well, like if i do trim(string) it will print trimmed string and when i print only string, it will print original string – avinashse 8 mins ago
Yes, though it gets silly.
You could modify the original string.
trim(string);
printf("trimmed: %s\n", string);
The advantage is you have the option of duplicating the string if you want to retain the original.
char *original = strdup(string);
trim(string);
printf("trimmed: %s\n", string);
If you don't want to modify the original string, that means you need to allocate memory for the modified string. That memory then must be freed. That means a new variable to hold the pointer so you can free it.
char *trimmed = trim(original);
printf("trimmed: %s\n", trimmed);
free(trimmed);
You can get around this by passing a function pointer into trim and having trim manage all the memory for you.
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
void trim(char *string, void(*func)(char *) )
{
// Advance the pointer to the first non-space char
while( *string == ' ' ) {
string++;
}
// Shrink the length to the last non-space char.
size_t len = strlen(string);
while(string[len-1]==' ') {
len--;
}
// Copy the string to stack memory
char trimmedStr[len + 1];
strncpy(trimmedStr,string, len);
// strncpy does not add a null byte, add it ourselves.
trimmedStr[len] = '\0';
// pass the trimmed string into the user function.
func(trimmedStr);
}
void print_string(char *str) {
printf("'%s'\n", str);
}
int main()
{
char string[]=" a sdf ie ";
trim(string, print_string);
printf("original: '%s'\n", string);
return 0;
}
Ta da! One variable, the original is left unmodified, no memory leaks.
While function pointers have their uses, this is a bit silly.
It's C. Get used to managing memory. ¯\_(ツ)_/¯
Also, is there any way where I don't have to charge original string as
well, like if I print trim(string) it will print trimmed string and
when i print only string, it will print original string
Yes you can, but you cannot allocate new memory in the trim function as you will not be holding the return memory.
You can have a static char buffer in the trim function and operate on it.
Updated version of #elcuco answer.
#include <stdio.h>
char *trim(char *string)
{
static char buff[some max length];
// trim prefix
while ((*string) == ' ' ) {
string++;
}
// find end of original string
int i = 0;
while (*string) {
buff[i++] = *string;
string++;
}
// trim suffix
while ((buff[i]) == ' ' ) {
buff[i] = '\0';
i--;
}
return buff;
}
int main()
{
char string1[] = " abcdefg abcdf ";
char *string = trim(string1);
printf("String is [%s]\n",string);
return 0;
}
With this you don't need to worry about holding reference to trim function return.
Note: Previous values of buff will be overwritten with new call to trim function.
If you don't want to change the original, then you will need to make a copy, or pass a second array of sufficient size as a parameter to your function for filling. Otherwise a simple in-place trmming is fine -- so long as the original string is mutable.
An easy way to approach trimming on leading and trailing whitespace is to determine the number of leading whitespace characters to remove. Then simply use memmove to move from the first non-whitespace character back to the beginning of the string (don't forget to move the nul-character with the right portion of the string).
That leaves only removing trailing whitespace. An easy approach there is to loop from the end of the string toward the beginning, overwriting each character of trailing whitespace with a nul-character until your first non-whitespace character denoting the new end of string is found.
A simple implementation for that could be:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define DELIM " \t\n" /* whitespace constant delimiters for strspn */
/** trim leading and trailing whitespace from s, (s must be mutable) */
char *trim (char *s)
{
size_t beg = strspn (s, DELIM), /* no of chars of leading whitespace */
len = strlen (s); /* length of s */
if (beg == len) { /* string is all whitespace */
*s = 0; /* make s the empty-string */
return s;
}
memmove (s, s + beg, len - beg + 1); /* shift string to beginning */
for (int i = (int)(len - beg - 1); i >= 0; i--) { /* loop from end */
if (isspace(s[i])) /* checking if char is whitespace */
s[i] = 0; /* overwrite with nul-character */
else
break; /* otherwise - done */
}
return s; /* Return s */
}
int main (void) {
char string1[] = " a sdf ie ";
printf ("original: '%s'\n", string1);
printf ("trimmed : '%s'\n", trim(string1));
}
(note: additional intervening whitespace was added to your initial string to show that multiple intervening whitespace is left unchanged, the output is single-quoted to show the remaining text boundaries)
Example Use/Output
$ ./bin/strtrim
original: ' a sdf ie '
trimmed : 'a sdf ie'
Look things over and let me know if you have further questions.
I have a gps string like below:
char gps_string[] = "$GPRMC,080117.000,A,4055.1708,N,02918.9336,E,0.00,316.26,00,,,A*78";
I want to parse the substrings between the commas like below sequence:
$GPRMC
080117.000
A
4055.1708
.
.
.
I have tried sscanf function like below:
sscanf(gps_string,"%s,%s,%s,%s,%s,",char1,char2,char3,char4,char5);
But this is not working. char1 array gets the whole string if use above function.
Actually i have used strchr function in my previous algorithm and got it work but it's easier and simplier if i can get it work with sscanf and get those parameters in substring.
By the way, substrings between the commas can vary. But the comma sequence is fixed. For example below is another gps string example but it does not contain some of its parts because of sattellite problem:
char gps_string[] = "$GPRMC,001041.799,V,,,,,0.00,0.00,060180,,,N*"
There have been a number of comments in other answers stating that there are a number of problems with strtok() and suggesting using strpbrk() instead. An example of how this is used can be found at Arrays and strpbrk in C
I do not have a compiler available so I could not test this. I could have typos or other misteaks in the code, but I am sure that you can figure out what is meant.
In this case you would use
char *String_Buffer = gps_string;
char *start = String_Buffer;
char *end;
char *fields[MAXFIELDS];
int i = 0;
int n = 0;
char *match = NULL;
while (end = strpbrk(start, ",")) // Get pointer to next delimiter
{
/* found it, allocate enough space for it and NUL */
/* If there ar two consecutive delimiters, only the NUL gets entered */
n = end - start;
match = malloc(n + 1);
/* copy and NUL terminate */
/* Note that if n is 0, nothing will be copied so do not need to test */
memcpy(match, start, n);
match[n] = '\0';
printf("Found field entry: %s\n", match);
/* Now save the actual match string pointer into the fields array*/
/* Since the match pointer is in fields, it does not need to be freed */
fields[i++] = match;
start = end + 1;
}
/* Check that the last element in the gps_string is not ,
Then get the final field, which has the NUL termination of the string */
n = strlen(start);
match = malloc(n + 1);
/* Note that if n is 0, only the terminator will be put in */
strcpy(match, start);
printf("Found field entry: %s\n", match);
fields[i++] = match;
printf("Total number of fields: %d\n", i);
You can use strtok:
#include <stdio.h>
int main(void) {
char gps_string[] = "$GPRMC,080117.000,A,4055.1708,N,02918.9336,E,0.00,316.26,00,,,A*78";
char* c = strtok(gps_string, ",");
while (c != NULL) {
printf("%s\n", c);
c = strtok(NULL, ",");
}
return 0;
}
EDIT: As Carey Gregory mentioned, strtok modifies the given string. This is explained in the man page I linked to, and you can find some details here too.
Please explain to me the working of strtok() function. The manual says it breaks the string into tokens. I am unable to understand from the manual what it actually does.
I added watches on str and *pch to check its working when the first while loop occurred, the contents of str were only "this". How did the output shown below printed on the screen?
/* strtok example */
#include <stdio.h>
#include <string.h>
int main ()
{
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, " ,.-");
}
return 0;
}
Output:
Splitting string "- This, a sample string." into tokens:
This
a
sample
string
the strtok runtime function works like this
the first time you call strtok you provide a string that you want to tokenize
char s[] = "this is a string";
in the above string space seems to be a good delimiter between words so lets use that:
char* p = strtok(s, " ");
what happens now is that 's' is searched until the space character is found, the first token is returned ('this') and p points to that token (string)
in order to get next token and to continue with the same string NULL is passed as first
argument since strtok maintains a static pointer to your previous passed string:
p = strtok(NULL," ");
p now points to 'is'
and so on until no more spaces can be found, then the last string is returned as the last token 'string'.
more conveniently you could write it like this instead to print out all tokens:
for (char *p = strtok(s," "); p != NULL; p = strtok(NULL, " "))
{
puts(p);
}
EDIT:
If you want to store the returned values from strtok you need to copy the token to another buffer e.g. strdup(p); since the original string (pointed to by the static pointer inside strtok) is modified between iterations in order to return the token.
strtok() divides the string into tokens. i.e. starting from any one of the delimiter to next one would be your one token. In your case, the starting token will be from "-" and end with next space " ". Then next token will start from " " and end with ",". Here you get "This" as output. Similarly the rest of the string gets split into tokens from space to space and finally ending the last token on "."
strtok maintains a static, internal reference pointing to the next available token in the string; if you pass it a NULL pointer, it will work from that internal reference.
This is the reason strtok isn't re-entrant; as soon as you pass it a new pointer, that old internal reference gets clobbered.
strtok doesn't change the parameter itself (str). It stores that pointer (in a local static variable). It can then change what that parameter points to in subsequent calls without having the parameter passed back. (And it can advance that pointer it has kept however it needs to perform its operations.)
From the POSIX strtok page:
This function uses static storage to keep track of the current string position between calls.
There is a thread-safe variant (strtok_r) that doesn't do this type of magic.
strtok will tokenize a string i.e. convert it into a series of substrings.
It does that by searching for delimiters that separate these tokens (or substrings). And you specify the delimiters. In your case, you want ' ' or ',' or '.' or '-' to be the delimiter.
The programming model to extract these tokens is that you hand strtok your main string and the set of delimiters. Then you call it repeatedly, and each time strtok will return the next token it finds. Till it reaches the end of the main string, when it returns a null. Another rule is that you pass the string in only the first time, and NULL for the subsequent times. This is a way to tell strtok if you are starting a new session of tokenizing with a new string, or you are retrieving tokens from a previous tokenizing session. Note that strtok remembers its state for the tokenizing session. And for this reason it is not reentrant or thread safe (you should be using strtok_r instead). Another thing to know is that it actually modifies the original string. It writes '\0' for teh delimiters that it finds.
One way to invoke strtok, succintly, is as follows:
char str[] = "this, is the string - I want to parse";
char delim[] = " ,-";
char* token;
for (token = strtok(str, delim); token; token = strtok(NULL, delim))
{
printf("token=%s\n", token);
}
Result:
this
is
the
string
I
want
to
parse
The first time you call it, you provide the string to tokenize to strtok. And then, to get the following tokens, you just give NULL to that function, as long as it returns a non NULL pointer.
The strtok function records the string you first provided when you call it. (Which is really dangerous for multi-thread applications)
strtok modifies its input string. It places null characters ('\0') in it so that it will return bits of the original string as tokens. In fact strtok does not allocate memory. You may understand it better if you draw the string as a sequence of boxes.
To understand how strtok() works, one first need to know what a static variable is. This link explains it quite well....
The key to the operation of strtok() is preserving the location of the last seperator between seccessive calls (that's why strtok() continues to parse the very original string that is passed to it when it is invoked with a null pointer in successive calls)..
Have a look at my own strtok() implementation, called zStrtok(), which has a sligtly different functionality than the one provided by strtok()
char *zStrtok(char *str, const char *delim) {
static char *static_str=0; /* var to store last address */
int index=0, strlength=0; /* integers for indexes */
int found = 0; /* check if delim is found */
/* delimiter cannot be NULL
* if no more char left, return NULL as well
*/
if (delim==0 || (str == 0 && static_str == 0))
return 0;
if (str == 0)
str = static_str;
/* get length of string */
while(str[strlength])
strlength++;
/* find the first occurance of delim */
for (index=0;index<strlength;index++)
if (str[index]==delim[0]) {
found=1;
break;
}
/* if delim is not contained in str, return str */
if (!found) {
static_str = 0;
return str;
}
/* check for consecutive delimiters
*if first char is delim, return delim
*/
if (str[0]==delim[0]) {
static_str = (str + 1);
return (char *)delim;
}
/* terminate the string
* this assignmetn requires char[], so str has to
* be char[] rather than *char
*/
str[index] = '\0';
/* save the rest of the string */
if ((str + index + 1)!=0)
static_str = (str + index + 1);
else
static_str = 0;
return str;
}
And here is an example usage
Example Usage
char str[] = "A,B,,,C";
printf("1 %s\n",zStrtok(s,","));
printf("2 %s\n",zStrtok(NULL,","));
printf("3 %s\n",zStrtok(NULL,","));
printf("4 %s\n",zStrtok(NULL,","));
printf("5 %s\n",zStrtok(NULL,","));
printf("6 %s\n",zStrtok(NULL,","));
Example Output
1 A
2 B
3 ,
4 ,
5 C
6 (null)
The code is from a string processing library I maintain on Github, called zString. Have a look at the code, or even contribute :)
https://github.com/fnoyanisi/zString
This is how i implemented strtok, Not that great but after working 2 hr on it finally got it worked. It does support multiple delimiters.
#include "stdafx.h"
#include <iostream>
using namespace std;
char* mystrtok(char str[],char filter[])
{
if(filter == NULL) {
return str;
}
static char *ptr = str;
static int flag = 0;
if(flag == 1) {
return NULL;
}
char* ptrReturn = ptr;
for(int j = 0; ptr != '\0'; j++) {
for(int i=0 ; filter[i] != '\0' ; i++) {
if(ptr[j] == '\0') {
flag = 1;
return ptrReturn;
}
if( ptr[j] == filter[i]) {
ptr[j] = '\0';
ptr+=j+1;
return ptrReturn;
}
}
}
return NULL;
}
int _tmain(int argc, _TCHAR* argv[])
{
char str[200] = "This,is my,string.test";
char *ppt = mystrtok(str,", .");
while(ppt != NULL ) {
cout<< ppt << endl;
ppt = mystrtok(NULL,", .");
}
return 0;
}
For those who are still having hard time understanding this strtok() function, take a look at this pythontutor example, it is a great tool to visualize your C (or C++, Python ...) code.
In case the link got broken, paste in:
#include <stdio.h>
#include <string.h>
int main()
{
char s[] = "Hello, my name is? Matthew! Hey.";
char* p;
for (char *p = strtok(s," ,?!."); p != NULL; p = strtok(NULL, " ,?!.")) {
puts(p);
}
return 0;
}
Credits go to Anders K.
Here is my implementation which uses hash table for the delimiter, which means it O(n) instead of O(n^2) (here is a link to the code):
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define DICT_LEN 256
int *create_delim_dict(char *delim)
{
int *d = (int*)malloc(sizeof(int)*DICT_LEN);
memset((void*)d, 0, sizeof(int)*DICT_LEN);
int i;
for(i=0; i< strlen(delim); i++) {
d[delim[i]] = 1;
}
return d;
}
char *my_strtok(char *str, char *delim)
{
static char *last, *to_free;
int *deli_dict = create_delim_dict(delim);
if(!deli_dict) {
/*this check if we allocate and fail the second time with entering this function */
if(to_free) {
free(to_free);
}
return NULL;
}
if(str) {
last = (char*)malloc(strlen(str)+1);
if(!last) {
free(deli_dict);
return NULL;
}
to_free = last;
strcpy(last, str);
}
while(deli_dict[*last] && *last != '\0') {
last++;
}
str = last;
if(*last == '\0') {
free(deli_dict);
free(to_free);
deli_dict = NULL;
to_free = NULL;
return NULL;
}
while (*last != '\0' && !deli_dict[*last]) {
last++;
}
*last = '\0';
last++;
free(deli_dict);
return str;
}
int main()
{
char * str = "- This, a sample string.";
char *del = " ,.-";
char *s = my_strtok(str, del);
while(s) {
printf("%s\n", s);
s = my_strtok(NULL, del);
}
return 0;
}
strtok() stores the pointer in static variable where did you last time left off , so on its 2nd call , when we pass the null , strtok() gets the pointer from the static variable .
If you provide the same string name , it again starts from beginning.
Moreover strtok() is destructive i.e. it make changes to the orignal string. so make sure you always have a copy of orignal one.
One more problem of using strtok() is that as it stores the address in static variables , in multithreaded programming calling strtok() more than once will cause an error. For this use strtok_r().
strtok replaces the characters in the second argument with a NULL and a NULL character is also the end of a string.
http://www.cplusplus.com/reference/clibrary/cstring/strtok/
you can scan the char array looking for the token if you found it just print new line else print the char.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *s;
s = malloc(1024 * sizeof(char));
scanf("%[^\n]", s);
s = realloc(s, strlen(s) + 1);
int len = strlen(s);
char delim =' ';
for(int i = 0; i < len; i++) {
if(s[i] == delim) {
printf("\n");
}
else {
printf("%c", s[i]);
}
}
free(s);
return 0;
}
So, this is a code snippet to help better understand this topic.
Printing Tokens
Task: Given a sentence, s, print each word of the sentence in a new line.
char *s;
s = malloc(1024 * sizeof(char));
scanf("%[^\n]", s);
s = realloc(s, strlen(s) + 1);
//logic to print the tokens of the sentence.
for (char *p = strtok(s," "); p != NULL; p = strtok(NULL, " "))
{
printf("%s\n",p);
}
Input: How is that
Result:
How
is
that
Explanation: So here, "strtok()" function is used and it's iterated using for loop to print the tokens in separate lines.
The function will take parameters as 'string' and 'break-point' and break the string at those break-points and form tokens. Now, those tokens are stored in 'p' and are used further for printing.
strtok is replacing delimiter with'\0' NULL character in given string
CODE
#include<iostream>
#include<cstring>
int main()
{
char s[]="30/4/2021";
std::cout<<(void*)s<<"\n"; // 0x70fdf0
char *p1=(char*)0x70fdf0;
std::cout<<p1<<"\n";
char *p2=strtok(s,"/");
std::cout<<(void*)p2<<"\n";
std::cout<<p2<<"\n";
char *p3=(char*)0x70fdf0;
std::cout<<p3<<"\n";
for(int i=0;i<=9;i++)
{
std::cout<<*p1;
p1++;
}
}
OUTPUT
0x70fdf0 // 1. address of string s
30/4/2021 // 2. print string s through ptr p1
0x70fdf0 // 3. this address is return by strtok to ptr p2
30 // 4. print string which pointed by p2
30 // 5. again assign address of string s to ptr p3 try to print string
30 4/2021 // 6. print characters of string s one by one using loop
Before tokenizing the string
I assigned address of string s to some ptr(p1) and try to print string through that ptr and whole string is printed.
after tokenized
strtok return the address of string s to ptr(p2) but when I try to print string through ptr it only print "30" it did not print whole string. so it's sure that strtok is not just returning adress but it is placing '\0' character where delimiter is present.
cross check
1.
again I assign the address of string s to some ptr (p3) and try to print string it prints "30" as while tokenizing the string is updated with '\0' at delimiter.
2.
see printing string s character by character via loop the 1st delimiter is replaced by '\0' so it is printing blank space rather than ''