249

I am trying to get a program to let a user enter a word or character, store it, and then print it until the user types it again, exiting the program. My code looks like this:

#include <stdio.h>

int main()
{
    char input[40];
    char check[40];
    int i = 0;
    printf("Hello!\nPlease enter a word or character:\n");
    gets(input);   /* obsolete function: do not use!! */
    printf("I will now repeat this until you type it back to me.\n");

    while (check != input)
    {
        printf("%s\n", input);
        gets(check);   /* obsolete function: do not use!! */
    }

    printf("Good bye!");
    
    return 0;
}

The problem is that I keep getting the printing of the input string, even when the input by the user (check) matches the original (input). Am I comparing the two incorrectly?

chqrlie
  • 131,814
  • 10
  • 121
  • 189
nmagerko
  • 6,586
  • 12
  • 46
  • 71
  • 17
    `gets( )` was removed from the standard. Use `fgets( )` instead. – lost_in_the_source Jan 29 '15 at 02:31
  • 1
    Note that this [answer](http://stackoverflow.com/a/595673/15168) to [Why does `strcmp()` return zero when its inputs are equal](http://stackoverflow.com/questions/595450/why-does-strcmp-return-0-when-its-inputs-are-equal) explains how to compare strings for equality, inequality, less than, greater than, less than or equal, and greater than or equal. Not all string comparisons are for equality. Case sensitive comparisons are different again; other special comparisons (dictionary order, for example) require more specialized comparators, and there are regexes for still more complex comparisons. – Jonathan Leffler Nov 22 '16 at 22:44
  • Note too that there is an essentially duplicate question [How do I check if a value matches a string](https://stackoverflow.com/questions/1598425/how-do-i-check-if-a-value-matches-a-string/) that was asked years before this. – Jonathan Leffler Feb 10 '17 at 05:24
  • Does this answer your question? [How do I check if a value matches a string](https://stackoverflow.com/questions/1598425/how-do-i-check-if-a-value-matches-a-string) – Andreas Jan 16 '20 at 03:37
  • 3
    This question is good, but the use of `gets()` is a no-go. It has also been removed from the standard since C11 -> Please read [Why is the gets function so dangerous that it should not be used?](https://stackoverflow.com/questions/1694036/why-is-the-gets-function-so-dangerous-that-it-should-not-be-used) – RobertS supports Monica Cellio May 30 '20 at 09:50

11 Answers11

364

You can't (usefully) compare strings using != or ==, you need to use strcmp:

while (strcmp(check,input) != 0)

The reason for this is because != and == will only compare the base addresses of those strings. Not the contents of the strings themselves.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Mysticial
  • 464,885
  • 45
  • 335
  • 332
  • 12
    the same in java,which may just compare with the address. – Telerik Sep 06 '14 at 16:29
  • 42
    Writing `while (strcmp(check, input))` is sufficient and is considered good practice. – Shravan Jun 28 '15 at 15:53
  • 10
    It is safer to use strncmp! Don't want a buffer overflow! – Floam Nov 10 '17 at 18:36
  • 1
    @Floam If you don't actually have strings, but zero-padded sequences of non-zero characters of known length, sure, that would be the right incantation. But that's something completely different! – Deduplicator Feb 01 '19 at 21:18
  • Unfortunately, while `gets` removes the trailing newline entered by the user when (s)he hits enter, `fgets` does not. To do that, type `buffer[strlen(buffer) - 1] = '\0';` That removes the newline. – ADBeveridge Aug 08 '21 at 03:19
  • 1
    @ADBeveridge `buffer[strlen(buffer) - 1] = '\0';` does not always work, and is in fact dangerous. `fgets()` does not always return a string that ends with a newline, so your code can remove valid data; and in fact `fgets()` can return a zero-length string, which means `buffer[strlen(buffer) - 1] = '\0';` will write outside the bounds of the array and invoke undefined behavior. See [**Removing trailing newline character from fgets() input**](https://stackoverflow.com/questions/2693776/removing-trailing-newline-character-from-fgets-input) – Andrew Henle Mar 16 '23 at 09:40
44

Ok a few things: gets is unsafe and should be replaced with fgets(input, sizeof(input), stdin) so that you don't get a buffer overflow.

Next, to compare strings, you must use strcmp, where a return value of 0 indicates that the two strings match. Using the equality operators (ie. !=) compares the address of the two strings, as opposed to the individual chars inside them.

And also note that, while in this example it won't cause a problem, fgets stores the newline character, '\n' in the buffers also; gets() does not. If you compared the user input from fgets() to a string literal such as "abc" it would never match (unless the buffer was too small so that the '\n' wouldn't fit in it).

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
AusCBloke
  • 18,014
  • 6
  • 40
  • 44
  • Can you please clarify the relationship/problem of "\n" and string literal? I am getting not equal result in comparing of strings (line) of a file with other whole file. – incompetent Jul 17 '19 at 16:32
  • 1
    @incompetent — if you read a line from a file with `fgets()`, then the string might be `"abc\n"` because `fgets()` keeps the newline. If you compare that with `"abc"`, you will get 'not equal' because of the difference between a null byte terminating `"abc"` and the newline in the read data. So, you have to zap the newline. The reliable one-line way to do that is `buffer[strcspn(buffer, "\n")] = '\0';` which has the merit of working correctly regardless of whether there is any data in the buffer, or whether that data ends with a newline or not. Other ways of zapping the newline easily crash. – Jonathan Leffler Jan 16 '20 at 03:39
  • This answer addresses the issues of the code accurately, while the most upvoted and accepted answer covers only to answer the question´s title. Especially to mention the last paragraph is super. +1 – RobertS supports Monica Cellio May 30 '20 at 09:49
17

Use strcmp.

This is in string.h library, and is very popular. strcmp return 0 if the strings are equal. See this for an better explanation of what strcmp returns.

Basically, you have to do:

while (strcmp(check,input) != 0)

or

while (!strcmp(check,input))

or

while (strcmp(check,input))

You can check this, a tutorial on strcmp.

Community
  • 1
  • 1
Box Box Box Box
  • 5,094
  • 10
  • 49
  • 67
11

You can't compare arrays directly like this

array1==array2

You should compare them char-by-char; for this you can use a function and return a boolean (True:1, False:0) value. Then you can use it in the test condition of the while loop.

Try this:

#include <stdio.h>
int checker(char input[],char check[]);
int main()
{
    char input[40];
    char check[40];
    int i=0;
    printf("Hello!\nPlease enter a word or character:\n");
    scanf("%s",input);
    printf("I will now repeat this until you type it back to me.\n");
    scanf("%s",check);

    while (!checker(input,check))
    {
        printf("%s\n", input);
        scanf("%s",check);
    }

    printf("Good bye!");

    return 0;
}

int checker(char input[],char check[])
{
    int i,result=1;
    for(i=0; input[i]!='\0' || check[i]!='\0'; i++) {
        if(input[i] != check[i]) {
            result=0;
            break;
        }
    }
    return result;
}
Shubham
  • 2,847
  • 4
  • 24
  • 37
mugetsu
  • 188
  • 1
  • 11
  • 1
    Could you please add more details about your solution? – abarisone Apr 06 '15 at 09:48
  • yes this is replacement for strcmp function and solition without using string.h header @Jongware – mugetsu Apr 06 '15 at 10:02
  • 3
    This does not work. When `checker` finds `'\0'` in one of the strings, it does not check the another string for `'\0'`. The function returns `1` ("equal") even if one string is only prefix of the other one (for example, `"foo"` and `"foobar"`). – lukasrozs Oct 06 '17 at 14:16
  • 2
    I would use `||` instead of `&&`. – lukasrozs Oct 06 '17 at 14:28
9

Welcome to the concept of the pointer. Generations of beginning programmers have found the concept elusive, but if you wish to grow into a competent programmer, you must eventually master this concept — and moreover, you are already asking the right question. That's good.

Is it clear to you what an address is? See this diagram:

----------     ----------
| 0x4000 |     | 0x4004 |
|    1   |     |    7   |
----------     ----------

In the diagram, the integer 1 is stored in memory at address 0x4000. Why at an address? Because memory is large and can store many integers, just as a city is large and can house many families. Each integer is stored at a memory location, as each family resides in a house. Each memory location is identified by an address, as each house is identified by an address.

The two boxes in the diagram represent two distinct memory locations. You can think of them as if they were houses. The integer 1 resides in the memory location at address 0x4000 (think, "4000 Elm St."). The integer 7 resides in the memory location at address 0x4004 (think, "4004 Elm St.").

You thought that your program was comparing the 1 to the 7, but it wasn't. It was comparing the 0x4000 to the 0x4004. So what happens when you have this situation?

----------     ----------
| 0x4000 |     | 0x4004 |
|    1   |     |    1   |
----------     ----------

The two integers are the same but the addresses differ. Your program compares the addresses.

not2qubit
  • 14,531
  • 8
  • 95
  • 135
thb
  • 13,796
  • 3
  • 40
  • 68
5

Whenever you are trying to compare the strings, compare them with respect to each character. For this you can use built in string function called strcmp(input1,input2); and you should use the header file called #include<string.h>

Try this code:

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

int main() 
{ 
    char s[]="STACKOVERFLOW";
    char s1[200];
    printf("Enter the string to be checked\n");//enter the input string
    scanf("%s",s1);
    if(strcmp(s,s1)==0)//compare both the strings  
    {
        printf("Both the Strings match\n"); 
    } 
    else
    {
        printf("Entered String does not match\n");  
    } 
    system("pause");  
} 
StephenTG
  • 2,579
  • 6
  • 26
  • 36
3

You need to use strcmp() and you need to #include <string.h>

The != and == operators only compare the base addresses of those strings. Not the contents of the strings

while (strcmp(check, input))

Example code:

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

int main()
{
    char input[40];
    char check[40] = "end\n"; //dont forget to check for \n

    while ( strcmp(check, input) ) //strcmp returns 0 if equal
    {
        printf("Please enter a name: \n");
        fgets(input, sizeof(input), stdin);
        printf("My name is: %s\n", input);
    }

    printf("Good bye!");
    return 0;
}

Note1: gets() is unsafe. Use fgets() instead

Note2: When using fgets() you need to check for '\n' new line charecter too

mustafa candan
  • 567
  • 5
  • 16
3

You can:

Use strcmp() from string.h, which is the easier version

Or if you want to roll your own, you can use something like this:

int strcmp(const char *s1, const char *s2)
{
    for (i = 0; s1[i] != '\0' || s2[i] != '\0'; i++)
    {
        if (s1[i] != s2[i])
        {
            return (unsigned char)s1[i] < (unsigned char)s2[i] ? -1 : 1;
        }
    }
    return 0;
}

I'd use strcmp() in a way like this:

while (strcmp(check, input))
{
    // code here
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
Anic17
  • 712
  • 5
  • 18
  • You probably meant to put a `return 0;` at the end of the strcmp function – Harrison Jul 19 '21 at 22:50
  • It's not needed, but yeah, it's a good practice – Anic17 Jul 20 '21 at 15:19
  • I took the liberty to fix the prototype and implementation of your `strcmp` function. It must return a negative or positive value according to the lexicographical order of the differing string arguments, and you forgot to initialize `i` to `0`: a `for` loop is less error prone than a `while` loop. Furthermore, your code returned 0 if either string is a prefix of the other. The final `return` is needed, otherwise the function would have undefined behavior for identical strings. – chqrlie Aug 10 '23 at 20:53
2

How do I properly compare strings?

char input[40];
char check[40];
strcpy(input, "Hello"); // input assigned somehow
strcpy(check, "Hello"); // check assigned somehow

// insufficient
while (check != input)

// good
while (strcmp(check, input) != 0)
// or 
while (strcmp(check, input))

Let us dig deeper to see why check != input is not sufficient.

In C, string is a standard library specification.

A string is a contiguous sequence of characters terminated by and including the first null character.
C11 §7.1.1 1

input above is not a string. input is array 40 of char.

The contents of input can become a string.

In most cases, when an array is used in an expression, it is converted to the address of its 1st element.

The below converts check and input to their respective addresses of the first element, then those addresses are compared.

check != input   // Compare addresses, not the contents of what addresses reference

To compare strings, we need to use those addresses and then look at the data they point to.
strcmp() does the job. §7.23.4.2

int strcmp(const char *s1, const char *s2);

The strcmp function compares the string pointed to by s1 to the string pointed to by s2.

The strcmp function returns an integer greater than, equal to, or less than zero, accordingly as the string pointed to by s1 is greater than, equal to, or less than the string pointed to by s2.

Not only can code find if the strings are of the same data, but which one is greater/less when they differ.

The below is true when the string differ.

strcmp(check, input) != 0

For insight, see Creating my own strcmp() function

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
-2
    #include<stdio.h>
    #include<string.h>
    int main()
    {
        char s1[50],s2[50];
        printf("Enter the character of strings: ");
        gets(s1);
        printf("\nEnter different character of string to repeat: \n");
        while(strcmp(s1,s2))
        {
            printf("%s\n",s1);
            gets(s2);
        }
        return 0;
    }

This is very simple solution in which you will get your output as you want.

-2

i just started coding and start watching the cs50 videos on youtube. there i encountered the problem, that you can´t compare two strings using "==". so i tryed it out:

#include <iostream>

using namespace std;

int main()
{

   string str[] = {"tom", "chris"};

   if (str[0] == "tom")
   {
       return 0;
   }

return 1;
}

For some reason the program works and returns 0. the video and the posts here say otherwise.

Bele
  • 25
  • 1
  • 4
    The program works because the array's first element and the string literal `"tom"` in the comparison happen to be the same global null terminated array of `char`. This is very common, but not guaranteed by the C Standard. Furthermore this comparison would not work for any other strings. Do not rely on this coincidence and use `strcmp()`. – chqrlie Aug 10 '23 at 11:12