Program can't compare Chars (C) - c

A function in my program is not executing the if statement and I'm not sure why. I checked if \n was a factor but it wasn't. Is this not the proper way to check if a char is a certain value?
void kitColour() {
printf("Enter the kit colour: ");
scanf("%s", &database[currentStorage].colours);
char *inputColour = database[currentStorage].colours;
printf("%s", inputColour);
// check if ROYGBIV
if (inputColour == 'R') {
printf("letter is R");
}
// skips previous if statement and executes this one
if (strlen(inputColour) == 1) {
currentStorage++;
mainMenu();
}
printf("Only the values 'R', 'O', 'Y', 'G', 'B', 'I', 'V' are acceptable.\n");
kitColour();
}
I tried to compare the user input to the value 'R' but it does not execute the if statement. I expected it to print "letter is R". Instead it skips the if statement and continues with the program.

In this if statement
if (inputColour == 'R') {
the left hand side operand inputColour has the pointer type char * due to its declaration
char *inputColour = database[currentStorage].colours;
That is you are trying to compare a pointer with a character.
You should write at least
if ( *inputColour == 'R') {
Also if the type of the expression database[currentStorage].colours is char then you have to use the conversion specifier c instead of s like
scanf( " %c", &database[currentStorage].colours );
and then
char inputColour = database[currentStorage].colours;
Pay attention to the leading space in the format string. It allows to skip white space characters.
Otherwise you have to write
scanf( "%s", database[currentStorage].colours );

Related

Loop back to question instead of printing out "Try again"? (C)

this is my first day coding and I'm trying to see how the code work, how can I change Y/N to Yes/No and loop back questions if the answer is not Yes instead of printing out "Try again?" or make it better?
int main(void)
{
char answer;
int name;
printf("Enter Username: \n");
scanf("%s",&name);
printf("Is your username \"%s\"? Enter Y or N\n", &name);
while (scanf(" %c", &answer) == 1 && answer == 'Y')
{
char answer2;
Sleep(1000);
printf("Username confirmed\n");
Sleep(2000);
int pass;
printf("Enter your password: \n");
scanf("%s",&pass);
printf("Is your password \"%s\"? Enter Y or N\n", &pass);
while (scanf(" %c", &answer2) == 1 && answer2 == 'Y')
{
printf("Success!");
Sleep(1000);
exit;
}
printf("Try again..\n");
Sleep(1000);
exit;
}
Sleep(1000);
printf("Try again..\n");
Sleep(1000);
exit;
return 0;
}
My best advice, as Weather Vane told you in the comment section, is to try to compile your code, before making changes: you'll find out that it won't even compile, since there are some errors (https://godbolt.org/z/MdahM4sT8).
You should debug and try to figure out why it doesn't work, fix it, then move to the new "features".
You probably want to change the while() condition and read a sequence of characters (array of char) instead of a single char.
char answer[4];
while (scanf("%3s", answer) > 0 && strcmp(answer, "Yes") == 0)
char answer[4]; creates an array of characters (which can be called a string, even though C doesn't have that abstraction) of size 4.
You might want to know why we need a size of 4, since the longer answer we can get is "Yes". Well, a string in C is a sequence of characters (char), ending with a special character, called terminating character '\0'.
Therefore, when you read a string with scanf(), you need to reserve some space for the terminating character aswell, and scanf() will add it when reading a space or carriage return after your input string. So if you enter "Yes" and then press the Return key, your answer[4] buffer will look like: {'Y', 'e', 's', '\0'}.
%3s tells scanf() to read only the first 3 characters of the string (prevents security issues like buffer overflow).
int scanf(const char *format, ...)
Description
Reads formatted input from stdin.
Return Value
On success, the function returns the number of items of the argument list successfully read. If a reading error happens or the end-of-file is reached while reading, the proper indicator is set (feof or ferror) and, if either happens before any data could be successfully read, EOF is returned.
Once you've read that string, you can use strcmp(), a function defined in `<string.h> header, that takes in 2 string parameters, and returns:
a negative value if the first precedes alphabetically the second;
0 if they're equal;
a positive integer if the second precedes alphabetically the second;
Therefore you can check if strcmp(answer, "Yes") == 0 to know if you've read Yes, and

Counting number of lines, words and characters while taking input as a string in loop

I am trying to solve the following problem in C language.
The input is taken as strings and user enters each string in new line. While user enters "END" , the program must stop taking input and should display the number of lines , words and characters. To achieve this I wrote the following code:
#include<stdio.h>
#include<string.h>
void main(){
char a[100], b = {'E', 'N', 'D'};
int i, k, word = 0, chr = 0, line = 0 ;
printf("Enter paragraph (enter END to stop)\n");
gets(a);
k = strcmp(a,b);
while (k != 0 ){
line++;
for (i = 0; a[i] != '\0'; i++){
if (a[i] == ' ')
word++;
else
chr++;
}
gets(a);
k = strcmp(a,b);
}
printf("%d %d %d\n", line, word, chr );
}
In the above code I assumed that the user is using only space button to give spaces between words.
The problems was
as soon as I give first input I get an error message saying program has stopped working.
I am not able to see whether my logic is wrong or my usage of syntax is wrong.
In the variable declaration
char a[100], b = {'E', 'N', 'D'};
b is declared as a scalar. This will lead to Segmentation Fault in strcmp(a,b) because both arguments of strcmp() must be pointers.
It should be
char a[100], b[] = "END";
you have to add [] to make b an array and you don't need to put each characters separately. Using string literal style initialization also have the compiler add terminating null-character so that you can pass that to strcmp() safely.
One more note is that you shouldn't use gets(), which has unavoidable risk of buffer overrun, deprecated in C99 and removed from C11. You can use fgets(), which can specify the length of the buffer, instead. fgets() stores newline character while gets() doesn't, so you have to remove that manually. This can be done like this, for example.
char a[100];
char *lf;
fgets(a, sizeof(a), stdin);
if ((lf = strchr(a, '\n')) != NULL) *lf = '\0';
Also I suggest you should use standard int main(void) in hosted environment instead of void main(), which is illegal in C89 and implementation-defined in C99 or later, unless you have some special reason to use non-standard signature.

printf("Enter 'a' : "); runs 2 times after 1st loop

int main (int argc, char *argv [])
{
char a = 'v';
for (int i = 0; a != 'x'; )
{
printf("Enter 'a' : ");
scanf("%c",&a);
}
return 0;
}
I ran it and gave input k. When I hit enter after this , why my printf runs 2 times when loop runs second times?
To understand this behaviour, we can simulate step-by-step the execution.
printf("Enter 'a' : ");
scanf("%c",&a); // User type in example 'a' and presses enter.
scanf "bufferize" a\n and places in a the value 'a'
The loop condition isn't satisfied, since 'a' == 'x' is false
printf("Enter 'a' : ");
scanf("%c",&a); // The buffer still contains `'\n'`
Since the buffer still contains unconsumed data, the next character ('\n') is placed in a and the loop continues.
The loop condition isn't satisfied, since '\n' == 'x' is false
printf("Enter 'a' : ");
scanf("%c",&a); // The buffer is empty now.
This gives you the illusion that the loop displays twice the printf, but in fact, the scanf kept reading the buffer without the need of user input.
If you enter more characters, in example qwerty, "Enter 'a' : " will be displayed 7 times, because "qwerty" contains 6 characters + '\n'
Note that using while (a != 'x') would suit better your needs than for (int i = 0; a != 'x'; )
When you use scanf and %c, it reads any character -- including the newline character you get when you press the ENTER key.
So if you run the program and type
a <Return>
you take two trips through the loop: one to read the 'a' and one to read the '\n'. If you type
<Space> <Space> a <Return>
it makes four trips through the loop. And if you type
x <Return>
it only makes one trip through the loop, because it notices you typed the 'x', and exits.
Things will become a little more clear if you print out each character you receive:
for (int i = 0; a != 'x'; )
{
printf("Enter 'a' : ");
scanf("%c",&a);
printf("you typed %d = %c\n", a, a);
}
When you see it printing
you typed 10 =
that's one of the newlines. (The value of '\n' is 10 in ASCII.)
I said that %c reads any character -- but that's somewhat unusual. Most of scanf's other format specifiers -- %d, %f, %s, etc. -- skip over "whitespace" -- that is, spaces, tabs, newlines, and a few others. But %c does not skip over those, because its job is to read exactly one character, and someone thought you might want to use it to read whitespace characters, too.
For starters this loop
for (int i = 0; a != 'x'; )
does not make sense at least because the variable i is not used within the loop.
Also this prompt
printf("Enter 'a' : ");
only confuses users. You are asking the user to enter the character 'a' while the loop stops when the character 'x' is entered.
This call of scanf
scanf("%c",&a);
reads all characters including white-space characters. It is the reason why the loop iterates one more. You have to write
scanf( " %c", &c );
^^^
In this case white spaces will be skipped.
From the C Standard (7.21.6.2 The fscanf function)
5 A directive composed of white-space character(s) is executed by
reading input up to the first non-white-space character (which remains
unread), or until no more characters can be read
The program can look the following way
#include <stdio.h>
int main(void)
{
char c;
do
{
printf( "Enter a character ('x' - exit): " );
} while ( scanf( " %c", &c ) == 1 && c != 'x' );
return 0;
}

Want to make c program app for bank

I have made the structure, but I'm stuck at the last point where I have to perform if/else coding. This is my very first program, using some tutorials on web.
The code is below:
#include<stdio.h>
#include<conio.h>
int main()
{
char fName;
char mName;
char lName;
int dob;
int branch;
int brcode;
char * pbprint;
printf("\tWELCOME TO BANK OF KANPUR :: ONE HAND ROLE TO YOUR SUCCESS");
printf("\n\n\n Customer Detail Form");
printf("\n ---------------------");
printf("\n\n\tCustomer Entity ");
printf("\n ");
printf("\n\n\n Customer's First Name : ");
scanf("%s", &fName);
printf("\n Customer's Middle Name : ");
scanf("%s", &mName);
printf("\n Customer's Last Name : ");
scanf("%s", &lName);
printf("\n\n\tDate of Birth ");
printf("\n ");
printf("\n\n\nDate[DD] : ");
scanf("%d", &dob);
printf("\nMonth[MM] : ");
scanf("%d", &dob);
printf("\nYear[YYYY] : ");
scanf("%d", &dob);
printf("\n\n\tBranch Details ");
printf("\n ");
printf("\n\n\nBranch Code : ");
scanf("%d", &brcode);
printf("\n\n\tPrinter ");
printf("\n ");
printf("\n\n\nWould You Like Us To Print Your Passbook [Y/N] : ");
scanf("%s", &pbprint);
// please help how to make if else statement here
// how to make the condition when if I enter yes it should show your
// printing is done else your printing is not done.
getchar();
return 0;
}
You are reading a string from console. If I understood, a simple way is to check only the first char from the string. You can do this:
if ( (pbprint[0] == 'Y') || (pbprint[0] == 'y') )
{
printf("your printing is done");
}
else
{
printf("your printing is not done");
}
The user is usually very creative, so you can choose how smart and versatile your input interface should be.
First of all change your variable declaration from char to char array, as you want strings to be entered. I am considering maximum you will enter 19 characters in strings so you variable declaration will look as below:
char fName[20];
char mName[20];
char lName[20];
char pbprint; // This is just character as you want single character input
You can change your taking character input as below:
printf("\n\n\nWould You Like Us To Print Your Passbook [Y/N] : ");
scanf(" %c",&pbprint); // Notice whitespace in the format string
if((pbprint == 'Y') || (pbprint == 'y')) // now you can do single character comparison
{
printf("Yes");
}
else
{
printf("No");
}
I hope this helps you to take single character input
Issue #1: You need to set aside space to store string data. The char datatype only allocates space for a single character value ('A', 'j', etc.). Strings are sequences of char values followed by a single 0-valued byte, so you need to set aside arrays of char large enough to hold a name plus the 0 terminator.
So, your name variables need to be declared as arrays of char:
#define NAME_LEN 30 // make this as big as you need
char fName[NAME_LEN + 1]; // Add a space for the 0 terminator
char mName[NAME_LEN + 1];
char lName[NAME_LEN + 1];
To read these using scanf, you would write
scanf( "%s", fName ); // note no & operator
The %s conversion specifier expects its corresponding argument to be a pointer to the first element of an array of char. Under most circumstances, an array expression (such as fname in the call above) will automatically be converted to a pointer, so you don't need to use the & operator in this case.
For safety's sake, you should check the result of the scanf call; it will return the number of successful conversions and assignments (0 if none of the conversions are successful), or EOF if it sees an end-of-file or error condition. You should also specify the maximum number of characters to be read within the conversion specifier; otherwise, if you type in more characters than your destination array is sized to hold, scanf will happily attempt to store those extra characters in the memory past the end of your array, leading to anything from corrupted data to a smashed stack to an outright crash:
if ( scanf( "%30s", fName ) == 1 ) // expect one successful conversion and assignment
{
// successfully read fName
}
else
{
// problem during read
}
Unfortunately, the length has to be "hard coded" into the conversion specifier. You can get around this by using some less-than-intuitive preprocessor macros:
#define S2(x) #x // surrounds x with double quotes
#define S1(x) S2(x) // causes x to be expanded before being passed to S2
#define E1(x) x // causes x to be expanded
#define FMT(x) S1(%E1(x)s) // writes a %xs conversion specifier, where
// x is the max length
Then you can write something like
if ( scanf( FMT(NAME_LEN), &fName ) == 1 )
which will expand out to
if ( scanf( "%30s", &fName ) == 1 )
The S2 and E1 macros look redundant, but they are necessary; you want to "expand" the argument x before applying the # operator to it. If we wrote
#define S1(x) #x
#define FMT(x) S1(%xs)
...
if ( scanf( FMT(NAME_LEN), &fName ) == 1 )
it would expand out to
if ( scanf( "%xs", &fName ) == 1 )
which is not what we want.
Issue #2: Simply declaring a pointer does not set aside storage for the thing you are pointing to. The declaration
char * pbprint;
creates the pointer variable pbprint, but it doesn't allocate any memory for the thing we want to point to. In this particular case, if all you want to store is a y or n value, then declare pbprint as a regular char and read using the %c conversion specifier, like so:
#include <ctype.h>
...
char pbprint;
...
if ( scanf( " %c", &pbprint ) == 1 ) // note leading blank in format string
{
if ( tolower( pbprint ) == 'y' ) // convert to lower case for comparison
{
// show print output
}
else
{
// don't show print output
}
}
else
{
// error on input
}
The leading blank before the %c conversion specifier is necessary to skip over any leading whitespace in the input stream; otherwise, you risk picking up a newline character from a previous entry, which isn't what you want here.
We also use the tolower library function (declared in ctype.h) to convert the input character to lower case for comparison. That way we don't have to write distinct branches for lowercase and uppercase letters.

Segmentation Fault, but I have no infinite loops... I think

New to C syntax, so perhaps I'm just making a dumb error. I'm trying to implement the strcat() function myself by using the exact same process. My copycat function is strcat406().
I keep getting segmentation fault as an error when trying to run the program.
EDIT: The first while loop in strcat406() is my attempt at getting around the strlen() function. I'm trying to avoid using the built in operations.
EDIT2: Okay, so as people pointed out, I replaced the '\n' to '\0'. Stupid mistake. Then I fixed the whole thing by removing the 'string1[i] = string[i]'. That way the first loop just iterates to determine i (the length of string1), then string2 is added to string1 in the second while loop. Corrections in code below.
#include <stdio.h>
char *strcat406(char string1[ ], char string2[ ]) {
int i = 0, j = 0;
while (string1[i] != '\0') { //replaced '\n' with '\0'
//removed: string1[i] = string1[i];
i++;
}
while (string2[j] != '\0') { //replaced '\n' with '\0'
string1[i+j] = string2[j];
j++;
}
string1[i+j] = '\0';
return string1;
}
int main() {
char str1[81], str2[81];
char again = 'y', newline;
while (again == 'y') {
printf("Enter a string\n");
scanf("%s", str1);
printf("Enter another string\n");
scanf("%s", str2);
printf("The concatention is %s\n", strcat406(str1, str2));
printf("Second test: The concatenation is %s\n", str1);
printf("The second string is still %s\n", str2);
printf("Again? (y/n)\n");
scanf("%c%c", &newline, &again);
}
}
The problem is that your while loops are looking for a newline character to terminate, but scanf("%s", ...) won't include the ending newline in the scanned string. You should look for '\0' to terminate those loops.
By the way... the title of this question reflects a misunderstanding. You said you're getting a segfault, but "have no infinite loops". Segfaults are not normally caused by infinite loops. They are commonly caused by dereferencing a null pointer, or a pointer which is "bad" in some other way. Note that array indexing is a form of pointer dereference, so using a "bad" array index is just the same thing.
A string is an array of characters containing a terminating null character '\0', not a newline character '\n'. Therefore, in strcat406 function, you should check the value for the null byte and not the newline character. Note that str2 must be large enough for string2 to be appended to it else it will cause buffer overflow invoking undefined behaviour. Also note that the lengths of both the strings string1 and string2 should each be less than 81 and the sum of their lengths should be less than 81 + 81 == 162.
#include <stdio.h>
char *strcat406(char string1[], char string2[]) {
int i = 0, j = 0;
// increment i till the terminating null byte is reached
while(string1[i++]) ; // the null statement
i--; // reset i to the index of the null byte
// copy the characters from string2 to string1 till and
// including the terminating null byte of string2
while((string1[i++] = string2[j++])) ; // the null statement
return string1;
}
int main(void) {
char str1[81], str2[81];
char again = 'y';
while(again == 'y') {
printf("Enter a string\n");
scanf("%s", str1);
printf("Enter another string\n");
scanf("%s", str2);
printf("The concatention is %s\n", strcat406(str1, str2));
printf("Second test: The concatenation is %s\n", str1);
printf("The second string is still %s\n", str2);
printf("Again? (y/n)\n");
// note the leading space in the format string of scanf.
// this reads and discards the newline left in the buffer in
// the previous scanf call
scanf(" %c", &again);
}
return 0;
}
The problem is that you are writing the result of the concatenation on top of one of the input strings. At the moment the first loop (over string1) does nothing; it is just copying string1 on top of itself character by character. I think you might be getting confused between the newline character '\n' and the string termination character '\0' as well.
The reason you are getting segfaults is that in the second loop you start writing onto the memory that follows the first input string. Only 81 characters of memory are reserved for it, but you might write more than that for the concatenation.
I think the answer would be to create a new string to contain the result of your function. You need to find out how long it needs to be by looping over the input strings first, counting their length. Then when you copy the two strings into the result you will only use the space that you have reserved for it in memory. Also you won't change the input as part of the function, which is another problem with the current method.

Resources