Checking equality of a string in C and printing an answer [duplicate] - c

This question already has answers here:
C Strings Comparison with Equal Sign
(5 answers)
Closed 9 years ago.
i've written some simple code as an SSCCE, I'm trying to check if string entered is equal to a string i've defined in a char pointer array, so it should point to the string and give me a result. I'm not getting any warnings or errors but I'm just not getting any result (either "true" or "false")
is there something else being scanned with the scanf? a termination symbol or something? i'm just not able to get it to print out either true or false
code:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#define LENGTH 20
//typedef char boolean;
int main(void)
{
const char *temp[1];
temp[0] = "true\0";
temp[1] = "false\0";
char var[LENGTH];
printf("Enter either true or false.\n");
scanf("%s", var);
if(var == temp[0]) //compare contents of array
{
printf("\ntrue\n");
}
else if(var == temp[1]) //compare contents of array
{
printf("\nfalse\n");
}
}

const char *temp[1];
This defines tmp an array that can store 1 char* element.
temp[0] = "true\0";
Assigngs to the first element. This is okay.
temp[1] = "false\0";
Would assign to the second element, but temp can only store one. C doesn't check array boundaries for you.
Also not that you don't have to specify the terminating '\0' explicitly in string literals, so just "true" and "false" are sufficient.
if(var == temp[0])
This compares only the pointer values ("where the strings are stored"), not the contents. You need the strcmp() function (and read carefully, the returned value for equal strings might not be what you expect it to be).

Use strcmp for comparing strings:
#include <stdio.h>
int main(void)
{
const int LENGTH = 20;
char str[LENGTH];
printf("Type \"true\" or \"false\:\n");
if (scanf("%19s", str) != 1) {
printf("scanf failed.");
return -1;
}
if(strcmp(str, "true") == 0) {
printf("\"true\" has been typed.\n");
}
else if(strcmp(str, "false") == 0) {
printf("\"false\" has been typed.\n");
}
return 0;
}
and also note that:
string literals automatically contain null-terminating character ("true", not "true\0")
const int LENGTH is better than #define LENGTH since type safety comes with it
"%19s" ensures that no more than 19 characters (+ \0) will be stored in str
typedef char boolean; is not a good idea
unlikely, but still: scanf doesn't have to succeed
and there is no #include <iostream> in c :)

== checks for equality. Let's see what you're comparing.
The variable var is declared as a character array, so the expression var is really equivalent to &var[0] (the address of the first character in the var array).
Similarly, temp[0] is equivalent to &temp[0][0] (the address of the first character in the temp[0] array).
These addresses are obviously different (otherwise writing var would automatically write temp[0] as well), so == will always return 0 for your case.
strcmp, on the other hand, does not check for equality of its inputs, but for character-by-character equality of the arrays pointed to by its inputs (that is, it compares their members, not their addresses) and so you can use that for strings in C. It's worth noting that strcmp returns 0 (false) if the strings are equal.

Related

Why do we need to check string length larger than 0?

I got this example from CS50. I know that we need to check "s == NULL" in case there is no memory in the RAM. But, I am not sure why do we need to check the string length of t before capitalize.
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
// Get a string
char *s = get_string("s: ");
if (s == NULL)
{
return 1;
}
// Allocate memory for another string
char *t = malloc(strlen(s) + 1);
if (t == NULL)
{
return 1;
}
// Copy string into memory
strcpy(t, s);
// Why do we need to check this condition?
if (strlen(t) > 0)
{
t[0] = toupper(t[0]);
}
// Print strings
printf("s: %s\n", s);
printf("t: %s\n", t);
// Free memory
free(t);
return 0;
}
Why do we need to use "if (strlen(t) > 0)" before capitalize?
Conceptually, there is no character to uppercase when the string is empty.
Technically, it's not needed. The first character of an empty string is 0, and toupper(0) is 0.
Note that strlen(t) > 0 can also be written as t[0] != 0 or just t[0]. There's no need to actually calculate the length of the string to find out if it's an empty string.
Also, make sure to read chux's answer for a correction regarding signed char.
// Why do we need to check this condition?
There is no need for the check. A string of length 0 consists of only a null character and toupper('\0'); returns '\0'.
Advanced: There is a need for something else though.
char may act as a signed or unsigned char. If t[0] < 0, (maybe due to entering 'é') then toupper(negative) is undefined behavior (UB). toupper() is only defined for EOF, (some negative) and values in the unsigned char range.
A more valuable code change, though pedantic, would be to access the characters as if they were unsigned char, then call toupper().
// if (strlen(t) > 0) { t[0] = toupper(t[0]); }
t[0] = (char) toupper(((unsigned char*)t)[0]);
// or
t[0] = (char) toupper(*(unsigned char*)t));
For any string t, the valid indexes (of the actual characters in the string) will be 0 to strlen(t) - 1.
Using strlen(t) as index will be the index of the null-terminator (assuming that it's a "proper" null-terminated string).
If strlen(t) == 0 then t[0] will be the null-terminator. And doing toupper on the null-terminator makes no sense. This is what the check does, make sure that there is at least one actual character (beyond the null-terminator) in the string.
In other words: It check that the string isn't empty.

How to input and compare a string [duplicate]

This question already has answers here:
scanf and strcmp with c string
(3 answers)
Closed 6 years ago.
I'm new to C and I need help.
This code doesn't work, even if I type London into the input I recieve the message from else: "Try again".
int main()
{
char capitalCity;
scanf("%s", &capitalCity);
if (capitalCity == 'London'){
printf("Is the capital city of UK.");
}
else{
printf("Try again.");
}
return 0;
}
There is no string data type in C programming language. Strings in C are represented as array of characters.
In C, char is a data type to represent a character (char in C represents the character type, suitable for storing a simple character—traditionally one from the ASCII encoding.). So, all you need to do is declare a array of char data type to represent a string in C. Each element in that array will hold a character of your string.
Also, operators in C like ==, !=, +=, + are defined for build-in data types in C and since, there is no operator overloading in C, you can't use these operators with your C-String as C-Strings are not build-in data type in C programming language.
Note: C-Strings are actually Null-terminated array of char data types. That means, last character in any C-String in C will be used to store a Null Character ('\0') which marks the end of the string.
The Header file has predefined functions that you can use to operate on C-String(Null-terminated array of char data type). You can read more about it over here.
So, your program should look like:
#define MAX_CSTR_LEN 100
int main()
{
char capitalCity[MAX_CSTR_LEN + 1]; ///An extra position to store Null Character if 100 characters are to be stored in it.
scanf("%s", capitalCity);
// Use strcmp to compare values of two strings.
// If strcmp returns zero, the strings are identical
if (strcmp(capitalCity, "London") == 0) {
printf("Is the capital city of UK.");
}
else {
printf("Try again.");
}
return 0;
}
Also, you have to use single quotes for character literals and double quotes for strings in C.
First, there are many things you need to learn. I'm trying my best to explain it to you.
In case of string as input, you can't compare by using == operator. you need to use strcmp() function which is declared in <string.h> header file, it compares character by character and return 0 if both string equal else a non-zero value.
#include <stdio.h>
#include <string.h> //for strcmp function
#define SIZE 30 //max size buffer for input
int main(){
char capitalCity[SIZE];
scanf("%s", capitalCity);
if(strcmp(capitalCity, "London") == 0){ //if(capitalCity == 'London') won't work in case of string comparison
printf("Is the capital city of UK.");
} else{
printf("Try again.");
}
return 0;
}
further reading http://www.geeksforgeeks.org/c/

'Scanf' for a String - Program crashing?

Why is this crashing when I input the string? I don't think I'm reading in the string right but the program gives me an error on the first 'scanf.' The program should be correct but this is C not C++. Most help that I could find was for C++.
//Andrei Shulgach
//April 27th, 2015
/*A string is a palindrome if it can be read forward and backward with the same
meaning. Capitalizations and spacing are ignored.*/
#include <stdio.h>
#include <stdlib.h>
int newStrCmp (const char *string1, const char *string2);
int main()
{
//Local Declarations
int dummy, value;
char string1[100],string2[100];
printf("Please enter the 1st string: ");
scanf_s("%99s", string1[100]);
printf("\nPlease enter the 2nd string: ");
scanf_s("%99s", string2[100]);
//Call Function and get value
value = newStrCmp(string1, string2);
if (value == 0)
printf("The strings are equal.\n");
else
printf("The strings are not equal.\n");
scanf_s("%d",&dummy);//Keep Window Open
return 0;
}
int newStrCmp (const char *string1, const char *string2)
{
//Local Declarations
int value = 0;
while (string1[value] == string2[value])
{
if (string1[value] == '\0' || string2[value] == '\0')
break;
value++;
}
if (string1[value] == '\0' && string2[value] == '\0')
return 0;
else
return -1;
}
You must enable all compiler warnings that you can get from your compiler; the above code shouldn't have compiled.
This:
scanf_s("%99s", string1[100]);
invokes undefined behavior since it indexes outside the 100-character string1 array. Remember that C arrays are indexed from 0. It also fails to comply with scanf_s()'s requirement that the size be specified for all string conversions.
It then probably1 causes more undefined behavior, when scanf_f() interprets a single character as a buffer address where input is to be stored (assuming the call happens, of course).
This is not valid code.
It should simply pass the address of the first character in the array:
scanf_s("%99s", string1, sizeof string1);
Here, string1 is the same as &string1[0]; the name of an array evaluates to the address of its first element in many contexts. We then use sizeof string1 as the third argument to specify the size of the string1 buffer, which is required.
1 You cannot reason about what happens after undefined behavior has happened with any certainty.
The issue is you are 'scanf'ing into index 100 of your length 100 buffer, i.e. out-of-bounds.
scanf_s("%99s", string1);
Also your comparison would be safer as a for loop that ensures value is less than 100, rather than a while loop.
In the future, please include the error message.

Why directly comparing string fails, but succeeds using char* [duplicate]

This question already has answers here:
Using the equality operator == to compare two strings for equality in C [duplicate]
(9 answers)
Closed 8 years ago.
In the following working code; instead of using *tofind, if I directly use the comparison
if(*argv[i] == "and")
it fails.
Why would that be?
/**
* Find index of the word "and"
* ./a.out alice and bob
*/
int main(int argc, char **argv) {
int i = 0;
char *tofind = "and";
while (argv[i] != NULL) {
if(*argv[i] == *tofind) {
printf("%d\n", i + 1);
break;
}
++i;
}
return 0;
}
if(*argv[i] == "and") shouldn't compile, I think you mean if (argv[i] == "and"), that would compare the pointers of the two, not the string content.
if (*argv[i] == *tofind) doesn't work as you expected either, it only compares the first character.
To compare strings, use strcmp():
if (strcmp(argv[i], tofind) == 0)
A "char*" is officially a pointer to a single char, for example to find points to a letter 'a'. You know that there are two more chars and a nul char, but officially it points to a single char.
Therefore, *argv[i] is the first character of an argument, and *tofind is always the letter 'a', so your code checks if the first character of an argument is an 'a'. Look at the strcmp function, which compares whole strings.
look at the type of
*argv[i] //its type is char
and of "and"
"and" //its type is const char * as it is decayed into pointer
so thats why you are unable to compare them.
while the type of
*tofind
is char and you can now compare the two.for more details see FAQs section 6.

Comparing 2 Strings, one in a struct other not C programming

I have this database and I Need to check whether a Product Name is already in the database otherwise I ask the user to input another one.
The problem is this:
I'm trying to compare a string (the Product Name) found inside the struct with the string the user inputs.
The coding of the struct, the user input part and the search method are here below:
product Structure
typedef struct
{
char pName[100];
char pDescription [100];
float pPrice;
int pStock;
int pOrder;
}product;
the checkProduct method:
int checkProduct (char nameCheck[100])
{
product temp;
p.pName = nameCheck;
rewind (pfp);
while (fread(&temp,STRUCTSIZE,1,pfp)==1)
{
if (strcmp (temp.pName,p.pName))
{
return 1;
}
}
return 0;
}
and the user input part [part of the code]:
char nameCheck[100];
gets (nameCheck);
checkProduct (nameCheck);
while (checkProduct == 1)
{
printf ("Product Already Exists!\n Enter another!\n");
while (getchar() !='\n')
{
continue;
}
}
p.pName = nameCheck;
Now I am having the following errors (I Use ECLIPSE):
on the line
while (checkProduct == 1) [found in the user input] is giving me:
"comparison between pointer and integer - enabled by default" marked by a yellow warning triangle
p.pName = nameCheck; is marked as a red cross and stopping my compiling saying:
"incompatible types when assigning to type 'char [100] from type 'char*'
^---- Is giving me trouble BOTH in the userinput AND when I'm comparing strings.
Any suggestions how I can fix it or maybe how I can deference it? I can't understand why in the struct the char pName is being marked as '*' whereas in the char[100] it's not.
Any brief explanation please?
Thank you in advance
EDIT: After emending the code with some of below:
THIS Is the INPUT NAME OF PRODUCT section;
char *nameCheck;
nameCheck = "";
fgets(nameCheck,sizeof nameCheck, stdin);
checkProduct (nameCheck);
int value = checkProduct (nameCheck);
while (value == 1)
{
printf ("Product Already Exists!\n Enter another!\n");
while (getchar() !='\n')
{
}
}
strcpy (p.pName, nameCheck);
this is the new checkName method
int checkProduct (char *nameCheck)
{
product temp;
strcpy (p.pName, nameCheck);
rewind (pfp);
while (fread(&temp,STRUCTSIZE,1,pfp)==1)
{
if (strcmp (temp.pName,p.pName) == 0)
{
return 1;
}
}
return 0;
}
p.pName = nameCheck;
is wrong as you try to assign address of one array to another. What you probably want is to copy it.
Use strcpy() instead.
strcpy(p.pName, nameCheck);
while (checkProduct == 1)
Since checkProduct is a function, the above condition will always be false as the address of function won't be equal to 1. You can store the return value in another integer like this:
int value = checkProduct(nameCheck);
while (value == 1)
/* rest of the code */
Or rather simply:
while ( checkProduct(nameCheck) == 1 ) {
...
Note - I've not checked entire code, there might be other bugs apart from this one. Btw, if you are new to programming, you can start with small examples from textbooks and then work towards slightly complex stuff.
int checkProduct (char nameCheck[100])
Note that the type signature is a lie. The signature should be
int checkProduct(char *nameCheck)
since the argument the function expects and receives is a pointer to a char, or, to document it for the user that the argument should be a pointer to the first element of a 0-terminated char array
int checkProduct(char nameCheck[])
Arrays are never passed as arguments to functions, as function arguments, and in most circumstances [the exceptions are when the array is the operand of sizeof, _Alignof or the address operator &] are converted to pointers to the first element.
{
product temp;
p.pName = nameCheck;
Arrays are not assignable. The only time you can have an array name on the left of a = is initialisation at the point where the array is declared.
You probably want
strcpy(p.pName, nameCheck);
there.
rewind (pfp);
while (fread(&temp,STRUCTSIZE,1,pfp)==1)
{
if (strcmp (temp.pName,p.pName))
strcmp returns a negative value if the first argument is lexicographically smaller than the second, 0 if both arguments are equal, and a positive value if the first is lexicographically larger than the second.
You probably want
if (strcmp(temp.pName, p.pName) == 0)
there.
gets (nameCheck);
Never use gets. It is extremely unsafe (and has been remoed from the language in the last standard, yay). Use
fgets(nameCheck, sizeof nameCheck, stdin);
but that stores the newline in the buffer if there is enough space, so you have to overwrite that with 0 if present.
If you are on a POSIX system and don't need to care about portability, you can use getline() to read in a line without storing the trailing newline.
checkProduct (nameCheck);
You check whether the product is known, but throw away the result. Store it in a variable.
while (checkProduct == 1)
checkProduct is a function. In almost all circumstances, a function designator is converted into a pointer, hence the warning about the comparison between a pointer and an integer. You meant to compare to the value of the call you should have stored above.
{
printf ("Product Already Exists!\n Enter another!\n");
while (getchar() !='\n')
You read in characters without storing them. So you will never change the contents of nameCheck, and then be trapped in an infinite loop.
{
continue;
}
If the only statement in a loop body is continue;, you should leave the body empty.
}
p.pName = nameCheck;
Once again, you can't assign to an array.
Concerning the edit,
char *nameCheck;
nameCheck = "";
fgets(nameCheck,sizeof nameCheck, stdin);
you have changed nameCheck from an array to a pointer. That means that sizeof nameCheck now doesn't give the number of chars you can store in the array, but the size of a pointer to char, which is independent of what it points to (usually 4 on 32-bit systems and 8 on 64-bit systems).
And you let that pointer point to a string literal "", which is the reason for the crash. Attempting to modify string literals is undefined behaviour, and more often than not leads to a crash, since string literals are usually stored in a read-only segment of the memory nowadays.
You should have left it at
char nameCheck[100];
fgets(nameCheck, sizeof nameCheck, stdin);
and then you can use sizeof nameCheck to tell fgets how many characters it may read, or, alternatively, you could have a pointer and malloc some memory,
#define NAME_LENGTH 100
char *nameCheck = malloc(NAME_LENGTH);
if (nameCheck == NULL) {
// malloc failed, handle it if possible, or
exit(EXIT_FAILURE);
}
fgets(nameCheck, NAME_LENGTH, stdin);
Either way, after getting input, remove the newline if there is one:
size_t len = strlen(nameCheck);
if (len > 0 && nameCheck[len-1] == '\n') {
nameCheck[len-1] = 0;
}
// Does windows also add a '\r' when reading from stdin?
if (len > 1 && nameCheck[len-2] == '\r') {
nameCheck[len-2] = 0;
}

Resources