-1

I have this code in my book, but I tried to understand it for a long time, but I couldn't. So, the code takes input from the user, and prints the outputs word per line along with the size of the word. It also prints the output based on the line. And it exclude any . , ! etc.. Example:

Input:

Hello, I am new here.
trying to learn.

Output:

Words typed on line number 1:
Hello(5)
I(1)
am(2)
new(3)
here(4)
Words typed on line number 2:
trying(6)
to(2)
learn(5)

Also, The code works on my friends computer, but not on mine. I keep getting an error message as you can see below. Can you please explain it to me? Also, why it doesn't work with me? and how can I fix it? I tried to use fgets, but it didn't work.

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

int main()
{
    char str[10][81];
    char* ptoken, * ptr;
    int i = 0, maxstr = 0;
    char* exclude = " .,!\t"; // I get an error message here (This entity cannot be initialized.)

    printf("Enter the text you want on multiple lines\n");
    printf("after you enter every thing pres ctrl+z and Enter \n\n");

    while (gets(str[i])) // I get an error message here (The identifier gets cant be found).
    {
        str[i++];
        maxstr++;
    }

    for (i = 0; i < maxstr; i++) {
        printf("\n<< Words typed on line number %d> \n", i + 1);
        ptr = str[i];
        ptoken = strtok(ptr, exclude);
        while (ptoken != NULL) {
            printf("strlen(%s) = %d\n", ptoken, strlen(ptoken));
            ptoken = strtok(NULL, exclude);
        }
    }

    return 0;
}

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
l Wawa
  • 43
  • 3
  • 2
    `gets` was removed from the language standard library because it's beyond evil and vile. Use `fgets`. (and tell your friend to stop using it too, even if they still have access to it). [Here is a nice QA for further reading](https://stackoverflow.com/questions/1694036/why-is-the-gets-function-so-dangerous-that-it-should-not-be-used). – WhozCraig Nov 19 '19 at 12:52
  • @WhozCraig I used fgets, it didn't work. – l Wawa Nov 19 '19 at 12:54
  • 1
    Not it the posted code, you didn't. And unrelated, this: `str[i++];` is odd; that should just be `++i;` – WhozCraig Nov 19 '19 at 12:55
  • If you want `fgets` to work with `strtok` you should add the newline `\n` to the delimiter character set. – Weather Vane Nov 19 '19 at 13:01
  • `char* exclude = " .,!\t"` -> `const char* exclude = " .,!\t"` – Jabberwocky Nov 19 '19 at 13:17
  • Which is the book are you talking about? There are some pretty bad books out there. You should probably throw it away and get a another one. – Jabberwocky Nov 19 '19 at 13:19

3 Answers3

2

char* exclude = " .,!\t"; // I get an error message here (This entity cannot be initialized.)

Attempting to modify a string literal gives undefined behavior. The const prevents you from doing that by accident (i.e., code that attempts to write via the pointer won't compile, unless you remove the const qualifier, such as with a cast).

char const *exclude =" .,!\t";


while (gets(str[i])) // I get an error message here (The identifier gets cant be found).

gets is deprecated because it's dangerous, it may cause buffer overflow.

Instead use fgets

while (fgets(str[i],sizeof(str),stdin))


Point to be noted

printf("strlen(%s) = %d\n", ptoken, strlen(ptoken));

Return type of strlen() in long int use %ld

printf("strlen(%s) = %ld\n", ptoken, strlen(ptoken));

Sathvik
  • 565
  • 1
  • 7
  • 17
  • The return type of `strlen()` is `size_t`, which is definitely *not* the same as `long int` because the two differ in signedness. `size_t` might or might not be the same type as `long unsigned int`, depending on the implementation. Any way around, though, the `printf` format is indeed incorrect. In a conforming C99 or later implementation, `%zu` would be the most appropriate formatting directive for an argument of type `size_t`. – John Bollinger Nov 19 '19 at 19:43
1

It seems you are compiling the program as a C++ program. If so then you need to write for example

const char *exclude = " .,!\t";
^^^^^

The function gets is not a standard C or C++ function. Instead ise the function fgets.

In this while loop

while (gets(str[i])) // I get an error message here (The identifier gets cant be found).
{
    str[i++];
    maxstr++;
}

these statements

    str[i++];
    maxstr++;

do not make sense.

Rewrite the loop like

for ( ; maxstr < 10 && fgets( str[maxstr], sizeof( str[maxstr] ), stdin ) != NULL; maxstr++ )
{
    str[maxstr][ strcspn( str[maxstr], "\n" )] = '\0';
}

I think this line

    str[maxstr][ strcspn( str[maxstr], "\n" )] = '\0';

requires an explanation. The function fgets can append the new line character '\n' to the entered string. To remove it (more precisely to substitute the character for the zero-terminating character '\0') there is used the string function strcspn that finds the position of the new line character. After that the substitution is done.

Substitute these two statements

    ptr = str[i];
    ptoken = strtok(ptr, exclude);

for

    ptoken = strtok( str[i], exclude);

that is the variable ptr is redundant.

And do not use magic numbers like for example 10. Use instead named constants.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
1

I keep getting an error message as you can see below. Can you please explain it to me?

Not precisely. Details depend somewhat on your compiler.

However, with respect to

   while (gets(str[i])) // I get an error message here (The identifier gets cant be found).

, the problem is surely with function gets(). This incurably flawed function should never be used, and in recognition of that, it was removed from the C language in the 2011 version of the standard. Most compilers still accept it, at least under some circumstances, but some do reject it. Whether macro _CRT_SECURE_NO_WARNINGS is defined might make a difference to your compiler in this regard.

On the other hand, there is nothing wrong with

   char* exclude = " .,!\t"; // I get an error message here (This entity cannot be initialized.)

as far as standard C is concerned, but it is nevertheless dangerous, because you are assigning exclude to point to a value that must not be modified, but that variable's type does not express the unmodifiablilty. A conforming compiler ought to accept the code anyway, but some will reject it under some circumstances.

Also, why it doesn't work with me? and how can I fix it?

The code has some subtle flaws, not limited to those I already mentioned, and whether any given compiler accepts it depends on the compiler and the compilation command. However, the two issues I've talked about can be resolved by

  • using fgets() instead of gets(). The former allows you to specify the size of the destination buffer, so that it is not overrun:

    while (fgets(str[i], 80, stdin) >= 0)
    

    Do note that there remain some peculiarities there, however, such as what happens when the input equals or exceeds 80 characters.

  • declaring exclude as a pointer to const char:

    const char *exclude = " .,!\t"; 
    
John Bollinger
  • 160,171
  • 8
  • 81
  • 157