Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use strtok()

I'm writing a C program to study the usage of function strtok(). Here is my code:

#include <stdio.h>
#include <string.h>

main() {
    char abc[100] = "ls &";
    char *tok;

    tok = strtok(abc, " ");
    while (tok != NULL) {
        printf("%s", tok);
        tok = strtok(NULL, " ");
    }
    printf("\n\n\n\n\n%s", tok);
    return 0;
}

It is printing the following output:

ls&




(null)

But I want it to print & at the second printf statement. How do I do it? I need this part for my homework project.

like image 455
user2201650 Avatar asked Feb 15 '23 05:02

user2201650


1 Answers

  1. Make sure you can identify the limits of what you print when you're printing.
  2. Output newlines at the end of printed messages; the information is more likely to appear in a timely manner if you do that.
  3. Don't print NULL pointers as strings; not all versions of printf() will behave nicely — some of them dump core.

Code:

#include <stdio.h>
#include <string.h>

int main(void)
{
    char abc[] = "ls &";
    char *tok;
    char *ptr = abc;

    while ((tok = strtok(ptr, " ")) != NULL)
    {
        printf("<<%s>>\n", tok);
        ptr = NULL;
    }
    return 0;
}

Or (optimized, courtesy of self.):

#include <stdio.h>
#include <string.h>

int main(void)
{
    char abc[] = "ls &";
    char *tok = abc;

    while ((tok = strtok(tok, " ")) != NULL)
    {
        printf("<<%s>>\n", tok);
        tok = NULL;
    }
    return 0;
}

Output:

<<ls>>
<<&>>

You can choose your own marker characters, but when not messing with XML or HTML, I find the double angle brackets reasonably good for the job.

You can also use your loop structure at the cost of writing a second call to strtok() (which is a minimal cost, but might be argued to violate the DRY principle: Don't Repeat Yourself):

#include <stdio.h>
#include <string.h>

int main(void)
{
    char abc[] = "ls &";
    char *tok = strtok(abc, " ");

    while (tok != NULL)
    {
        printf("<<%s>>\n", tok);
        tok = strtok(NULL, " ");
    }
    return 0;
}

Same output.


Revised requirement

I would like to add a printf() statement outside the while loop and print '&' outside. I need it since I want to compare it later with another variable in the program. Is there any way to do so?

Yes, there is usually a way to do almost anything. This seems to work. It also works sanely if there are more tokens to parse, or if there's only the & to parse, or if there are no tokens. Clearly, the body of the outer loop could be made into a function if you so wished; it would be sensible to do so, even.

#include <stdio.h>
#include <string.h>

int main(void)
{
    char tests[][16] =
    {
        "ls -l -s &",
        "ls &",
        "&",
        "    ",
        ""
    };

    for (size_t i = 0; i < sizeof(tests)/sizeof(tests[0]); i++)
    {
        printf("Initially: <<%s>>\n", tests[i]);
        char *tok1 = strtok(tests[i], " ");
        char *tok;

        while ((tok = strtok(NULL, " ")) != NULL)
        {
            printf("Loop body: <<%s>>\n", tok1);
            tok1 = tok;
        }
        if (tok1 != NULL)
            printf("Post loop: <<%s>>\n", tok1);
    }

    return 0;
}

Output:

Initially: <<ls -l -s &>>
Loop body: <<ls>>
Loop body: <<-l>>
Loop body: <<-s>>
Post loop: <<&>>
Initially: <<ls &>>
Loop body: <<ls>>
Post loop: <<&>>
Initially: <<&>>
Post loop: <<&>>
Initially: <<    >>
Initially: <<>>

Note how the markers pay for themselves in the last two examples. You couldn't tell those apart without the markers.

like image 127
Jonathan Leffler Avatar answered Feb 25 '23 05:02

Jonathan Leffler