1

I'm writing a program to find the smallest and largest word according to the dictionary order in K.N.King's problem. Find the largest and smallest of a word until the user inputs a 4 letter word.

Firstly, I use strcmp to compare the input word with the largest or smallest. then using strcpy to copy the input string to the largest or smallest.

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

main()
{
    char inputStr[20] ;
    char max[20];
    char min[20];
    int length =0;
    do
    {
        printf("pls, input your string: ");
        gets(inputStr);
        if(strcmp(inputStr,max) > 0)
            strcpy(max,inputStr);
        if (strcmp(inputStr,min) < 0)
            strcpy(min,inputStr);

        length = strlen(inputStr);  
    }
    while (length != 4);
        printf("largest word is: %s\n",max);
        printf("smallest word is: %s",min); 

}

for example.

Enter Word : Cat
Enter Word : Dog
Enter Word : penguin
Enter Word : bear

the smallest word is bear
the largest word is penguin

However, when running programs, the largest word is always a special character, and the smallest is always right. My program shows the result that

the largest word is:         
 the smallest word is: bear
iBug
  • 35,554
  • 7
  • 89
  • 134

4 Answers4

2

You don't asctually initialise max or min so they will be set to arbitrary values when you first compare them.

You can fix this by simply doing setting them to the first word regardless of the comparison:

int firstTime = 1;
do
{
    printf("Please input your string: ");
    gets(inputStr);
    if (firstTime || (strcmp(inputStr, max) > 0))
        strcpy(max, inputStr);
    if (firstTime || (strcmp(inputStr, min) < 0))
        strcpy(min, inputStr);
    firstTime = 0;
    length = strlen(inputStr);  
}

And, as an aside, there's a reason why gets was deprecated and later removed from the standard, there is no way to protect against buffer overflow if you use this function. Further details can be found here, which also includes a very handy solution to the problem.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
1

I suspect the main issue is that either max or min will always be the incorrect, as they are empty (or filled with garbage) to begin with. You should reformat your code to be in the style:

min = max = initial-input()
length = len(min)

while (length != 4) 
    do stuff

I also recommend using fgets() or getline() for reading input, just in case you decide to put in 100 characters when you only set aside space for 20. Same with strcpy(), it should be replaced by strncpy() just in case. So the result will look something like:

...
fgets(inputStr, 20, stdin);
strncpy(max, inputStr, 20);
strncpy(min, inputStr, 20);
length = strlen(inputStr);

while(length != 4) {
     ...
}
Jacob H
  • 864
  • 1
  • 10
  • 25
  • Be aware that `strncpy` can have performance penalties with larger strings or when called repeatedly within a loop due to it zeroing all memory beyond the first terminating nul-character. See [c - What is the best alternative to strncpy()?](https://stackoverflow.com/questions/41869803/what-is-the-best-alternative-to-strncpy) – David C. Rankin Dec 16 '17 at 07:56
  • can you explain to me? I'm wrong because I don't initialize max and min. However, the program still runs with min. why is that? – Vũ Đức Dũng Dec 16 '17 at 08:59
  • @VũĐứcDũng well suppose that min contains the string "zzz" before any input, just by chance. Then it will probably be overwritten. Do the answer basically could down to luck. If you run this a week from now you might find that only max works, or perhaps neither works. – Jacob H Dec 16 '17 at 12:57
1

The problem is due to uninitialized char array. This(using it in strcmp) is undefined behavior. Also logically your code won't work properly. strcasecmp is not part of standard - it is a POSIX thing.

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define MAXLETTER 20
int main(void)
{
    char inputStr[MAXLETTER] ;
    char max[MAXLETTER];
    char min[MAXLETTER];
    size_t length =0;
    bool flag = true;
    do
    {
        printf("pls, input your string: ");
        if( fgets(inputStr,sizeof inputStr,stdin) == NULL){
            fprintf(stderr, "%s\n", "Error in input");
            exit(1);
        }
        inputStr[strcspn(inputStr,"\n")]='\0';
        if(flag){
            strncpy(max,inputStr,MAXLETTER-1);
            strncpy(min,inputStr,MAXLETTER-1);
            max[MAXLETTER-1]=0;
            min[MAXLETTER-1]=0;
            flag = false;
        }
        if(strcasecmp(inputStr,max) > 0){
            strncpy(max,inputStr,MAXLETTER-1);
            max[MAXLETTER-1]=0;
        }            
        if (strcasecmp(inputStr,min) < 0){
            strncpy(min,inputStr,MAXLETTER-1);
            min[MAXLETTER-1]=0;
        }
        length = strlen(inputStr);  
    }
    while (length != 4);
    printf("largest word is: %s\n",max);
    printf("smallest word is: %s",min); 
    return 0;
}

Compile your program using gcc -Wall -Wextra -Werror progname.c, it will tell you where you are going wrong.

One thing, Don't use gets().

I'm wrong because I don't initialize max and min. However, the program still runs with min...

The thing it is called Undefined behavior. It may work some time and may not. That's the thing about it. Without initializzing when you compare then behavior is not defined. It may get some error , may suprisingly give correct result.

user2736738
  • 30,591
  • 5
  • 42
  • 56
  • `strncpy(max,inputStr,MAXLETTER);` has no benefit over `strcpy(max,inputStr);` here. Usage of `strncpy()` unclear here. – chux - Reinstate Monica Dec 16 '17 at 05:16
  • @chux.: Correct me if I am wrong, earlier case still it would miss the case of not writing \0` here we do it so that 19 letters are read at most. 20th char is always `\0`. – user2736738 Dec 16 '17 at 05:45
  • `strncpy()` does not affect "we do it so that 19 letters are read at most.". That is due to `fgets()`. "20th char is always \0." is true with this application's use of `strncpy()`, yet that is not important. What is important is that `inputStr` has a null character _where it should_. Insuring "20th char is always \0." is [belt and suspenders](https://stackoverflow.com/a/768164/2410359). – chux - Reinstate Monica Dec 16 '17 at 14:51
0

Revised

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

#define N 20

int main( void )
{

    char max[N];
    char min[N];
    char (*ch)[N];
    char inputStr[N] ;
    int length = 0;


    fgets(inputStr, sizeof(inputStr), stdin);

    // Technique from https://stackoverflow.com/a/28462221/701302
    inputStr[strcspn(inputStr, "\n")] = 0;

    // Set both max and min to initial input  in order to ...
    strcpy(max,inputStr);
    strcpy(min,inputStr);

    do
    {
        fgets(inputStr, sizeof(inputStr), stdin);

        inputStr[strcspn(inputStr, "\n")] = 0;

        // ... now have basis for valid comparison
        if (strcmp(inputStr,max) > 0){ 
            strcpy(max,inputStr);
        }
        else
        if ( strcmp(inputStr,min)  < 0){
            strcpy(min,inputStr);
        }    
        length = strlen(inputStr);  
    } while (length != 4);

     printf("largest word is: %s\n",max);

     ch = &min;
     if (strcmp(ch,"") == 0){
        ch = "[empty string]";
     }
     printf("smallest word is: %s",ch); 

}

See live code.

Note: it is much safer to use fgets() than gets(). The reason gets() is dangerous is b/c of potential buffer overflows per this article. However, with fgets() the input may terminate with a newline so you need to get rid of it. Although you may use strtok() for that even tho' it wasn't designed with that possibility in mind, as chux remarks it is inadequate if the user's input consists of a newline character.

I revised this answer again, taking a cue from here. The technique utilizes strcspn() which returns the number of characters in str1 not in str2, So, the newline gets replaced every time whether the input consists of one or more printable characters or a newline. I accordingly revised both the code and input at ideaone.com. So, now the output reflects the largest word is penguin and the smallest word is the empty string. But, if you run the code using only the original input of the OP, then the result will be penguin and bear as respectively the largest and smallest words lexicographically speaking.

slevy1
  • 3,797
  • 2
  • 27
  • 33