Why program is giving unexpected output? - c

I'm stuck in a problem given in a book. The problem is -
The prototypical Internet newbie is a fellow name B1FF,who has a unique way of wriring messages.Here’s a typical B1FF communique.:
H3Y DUD3, C 15 R1LLY C00L
Write a “B1FF filter” that reads a message entered by the user and translates it into B1FF-speak:
Enter message: Hey dude, C is rilly cool
In B1FF-speak : H3Y DUD3, C 15 R1LLY C00L
Your program should convert the message to upper-case letters,substitute digits for certain letters (A=4,B=8,E=3,I=1,O=0,S=5).
My Program-
#include<stdio.h>
int main()
{
char arr[50]={0},ch[50]={0};
int i=0;
printf("\nenter the sentence : ");
while(arr[i-1]!='\n')
{
scanf("%c",&arr[i]);
i++;
}
i=0;
while(arr[i]!='\n')
{
if(arr[i]=='e')
ch[i]='3';
if(arr[i]==('A'||'a') )
ch[i]='4';
if(arr[i]==('B'||'b'))
ch[i]='8';
if(arr[i]==('I'||'i'))
ch[i]='1';
if(arr[i]==('o'||'O'))
ch[i]='0';
if(arr[i]==('S'||'s'))
ch[i]='5';
else ch[i]=arr[i]-32;
i++;
}
ch[i]='\n';
i=0;
printf("\nIn B1FF-SPEAK : ");
while(ch[i]!='\n')
{
printf("%c",ch[i]);
i++;
}
printf("\n");
return 0;
}
OUTPUT OF THE PROGRAM-
I don't understand why the program is not converting the alphabets and why scanf() is not accepting space as a character ?

First and foremost, you cannot chain the logical OR operator like
if(arr[i]==('A'||'a') )
and get what you're expecting, because this resolves to an always TRUE condition. [('A'||'a') evaluates to TRUE]
You have to use
if ( (arr[i]=='A') || (arr[i] =='a'))
That said,
ch[i]=='8';, ch[i]==1; are basically empty statements. You're comparing and discarding the comparison result. If you want assignment, you need to use =.
the else ch[i]=arr[i]-32; only binds with the previous if statement, no the whole if chains. You can either make use of switch case or if-else if-else constructs to take care of that part.
you did not handle whitespaces separately.
To elaborate, due to the second point above, you code basically reduces to
while(arr[i]!='\n')
{
if(arr[i]==('S'||'s')) //always false
ch[i]='5';
else ch[i]=arr[i]-32; //always TRUE
i++;
}
which is just a poor attempt to convert lowercase to UPPERCASE. In case a non-alpha input is there in the string, the code will blow up.
That said, regarding the
why scanf() is not accepting space as a character?
part, scanf() perfectly accepts a space as an input with %c, it's you just convert it no NUL (null) by blindly subtracting 32 from a space which has an ASCII value of decimal 32. A NUL is non printable, and does not appear in the output.

Some recommendations:
Don't use lots of little calls to scanf("%c"...). Use fgets() (manpage). fgets reads in a whole line from input, stores it in your buffer (including the newline), and sticks a '\0' byte at the end of it so you know how long the string is.
use toupper() (manpage). It takes an arbitrary character as input. If the input is a lower case letter, then the output is the upper-case version of that letter. Otherwise, the output is the same as the input.
Update the array in-place. You don't need two arrays. Read the array with fgets(), loop over it with your translation logic, updating each character as you go, then write the array out with fputs().
Learn about switch statements. A switch statement will make your code more compact and easier to read. You need one case for every letter->number transform, and a default case for everything else.
c = toUpper(c);
switch (c) {
case 'A': c = '4'; break;
case 'B': c = '8'; break;
....
default: break;
}

Related

Character input function through pointers is not yielding a response

As part of a larger code repository, I replicated the gets() function by creating my own. The function merely accepts characters into a character array until it encounters a newline character or detects that the string length has been breached. The code is as follows:
void word_enter(char *word_search)
{
char r;
char *m=word_search;
printf("Enter the word to search for: ");
while((r==getchar())!=EOF)
{
if(r=='\n' || m==&word_search[WORD_LEN-1])
{
*m=0;
break;
}
else
{
*(m++)=r;
}
}
}
Apropos WORD_LEN, its value has been defined as 25 by the #define directive.
The function, however, doesn't work properly, and is rather jittery. Inputting a newline does not make the function cease, and the cursor merely shifts to the next line. What explains this? I've been bawling my hearts out figuring out as to what the error is, but to no avail. Be advised that while I'm awfully cognisant of the fact the string.h library has the same function under its belt, I intend to create mine from scratch.
You are comparing r with the return of getchar():
while((r==getchar())!=EOF)
What you should do instead is to assign the return value of getchar() to r:
while((r=getchar())!=EOF)

Making a more efficient function - Word counter

I'm going through some C programming questions and I want to make sure I got the fundamentals down. Currently I'm on a word counter question:
Q: Write a function which will determine how many words are in a given string. You can assume that one or more
consecutive white spaces is a delimiter between words, and that the string you pass to your function is null terminated.
I got the thing working, but efficiency is important. I'm wondering how it can be improved. Have to use pointers and no other library besides #include(stdio.h) Thanks!
#include <stdio.h>
int word_counter(char string[])
{
//We start with first word unless we have a empty string then we have no words
int count;
if(*string!='\0'){
count=1;
}
else{
count=0;
return 0;
}
//while we dont reach the end of the string
while(*string!='\0'){
//if we detect a whitespace
if(*string==' '){
//get previous character
string--;
// If previous character is not a space we increase the count
// Otherwise we dont since we already counted a word
if(*string!=' '){
count++;
}
//return pointer to current character
string++;
}
// set pointer to next character
string++;
}
return count;
}
//just to test if it works
int main(void)
{
char str[] = "Hello World!";
printf("How many words? = %i\n", word_counter(str));
return 0;
}
Looking at your code, I see there's a special case for the initial condition of an empty string. Sometimes getting the initial condition out of the way early simplifies the rest of the algorithm, sometimes you can eliminate it by changing how you look at the problem. This time it's the second one.
If you think about this as counting the boundaries between words, the algorithm becomes simpler. There's two ways to define a word boundary, from the front, and from the back.
" Prestidigitation \n"
^ ^
front back
Are we looking for a non-whitespace character after a whitespace character? Or are we looking for a whitespace character after a non-whitespace character?
You also have code that looks backwards in the string (string--), that's often not safe because what if the string starts with whitespace? Then you've walked backwards off the string, so moving backwards should be avoided.
Finally, there's the problem of whether or not there's any whitespace at the end of the string. We'd have to special case the end of the string.
So looking at the first word boundary is the way to go: a non-whitespace character after a whitespace character. Instead of looking backwards, we'll track the state of the previous character (last_was_space below).
That's a non-whitespace character after a whitespace character. What if the string doesn't start with whitespace?
"Basset hounds got long ears."
^
What about this?
Since we have last_was_space, we can initialize it to true and pretend the start of the string starts with whitespace. This also handles leading whitespace like " this is four words".
Finally, there's more types of space than just space like tab and newline and other exotic stuff. Instead of writing if( *space == ' ' || *space == '\n' == ... ) we can use switch to make things tidy and efficient. This is one of those rare cases where you want to take advantage of its "fall through" mechanic to do the same thing for multiple cases.
#include <stdio.h>
// Note that it's `const` since we don't touch the string memory.
int word_counter(const char string[]) {
// Start with no words.
int count = 0;
// Pretend every word starts with space.
short last_was_space = 1;
// Using a for loop to make the movement of the pointer more apparent
for( ; *string!='\0'; string++ ) {
// A switch can be faster than an if/else if.
switch( *string ) {
// There's more than one type of whitespace.
// These are from isspace().
// It takes advantage of switch's fall through.
case ' ':
case '\t':
case '\n':
case '\r':
case '\v':
case '\f':
// Remember we saw a space.
last_was_space = 1;
break;
default:
if( last_was_space ) {
// Non-whitespace after space, count it
count++;
// Remember we didn't see a space.
last_was_space = 0;
}
break;
}
}
return count;
}
Normally I'd use bool from stdbool.h and isspace from ctype.h, but your exercise can only use stdio.h.

c program for word ladder

I have written C code for word ladder.
It is validating for given test cases. but for 1 test case it's output is wrong I'm not getting where should I make changes.
Question
There is a class of word puzzles where you are given two words, such as BEAK and MAKE, and have to get from one to another by changing one letter at a time. Solving such puzzles requires a good vocabulary and some lateral thinking, but checking the solution once you have one is merely tedious and suitable for a computer to do. Note that even correct solutions are not guaranteed to be minimal.
A solution is correct if, for each pair of adjacent words in the ladder, the following apply:
they are the same length
there is exactly one letter changed.
Write a program that will check proposed solutions.
Input Format:
Input will be a solution i.e it consists of a series of words, one per line, terminated
by a line containing a single #. A word is a sequence --- between three and twenty uppercase letters.
Output Format:
Output the word ‘Correct’ or ‘Incorrect’ as appropriate.
Sample Input 1:
BARK
BARE
#
Sample Output 1:
Correct
Sample Input 2:
MAKE
BAKE
BONK
BONE
BANE
#
Sample Output 2:
Incorrect
My code
#include<stdio.h>
#include<string.h>
int main()
{
int i,count;
char a[100],b[100],c[100];
int flag=1;
scanf("%s",a);
do
{
scanf("%s",b);
if(b[0]=='#')
break;
if(strlen(a)==strlen(b))
{ i=0,count=0;
while(a[i]!='\0')
{
if(a[i]!=b[i])
count++;
if(count==2)
{
flag=0;
}
i++;
}
}
else
{
flag=0;
}
scanf("%s",a);
if(a[0]=='#')
break;
// scanf("%s",c);
strcpy(c,a);
strcpy(a,b);
strcpy(b,c);
}
while(a[0]!='#');
if(flag==1)
printf("Correct");
else
printf("Incorrect");
return 0;
}
programs output is incorrect for this input
code -> cade -> cate -> date -> data
You are reading words too many times. I mean, you read more than you compare.
Check this out:
first scanf() (into a) doesn't count. It's used to have something to compare
second scanf() (into b) in the loop
comparison of a and b in the loop
third scanf() (into a) in the loop!!
repeat at 2.
You should only have 1 scanf() and 1 comparison inside the loop.
Also your indentation hurts.

Ending a loop when fscanf reads a certain value from a text file

I'm trying to write a program that reads a character and a float from a text file and then saves these values to a variable.
The text file is formatted in this manner:
S 15.24
G 28.00
S 56.90
H 90.00
0
I'm attempting to have the character be read and then have it run through a switch to do a few calculations based on which character comes before the float(all S values are grouped together, all G values are grouped together, etc)
To have it go through all the lines available, I'm using a while loop that terminates when the read character reaches the 0 at the end of the list.
Just for testing purposes I'm having the program print "Done" when it exits the loop. However when I run the program, it runs through every character and prints it properly to the terminal until its printed the values before 0. once it reaches the 0, the program doesn't do anything else, but it doesn't print "Done" like I assumed it should.
This is the code I'm using:
int main()
{
int s_num,g_num,h_num,S,H,G,n_total;
float amount,s_total,s_sum,g_sum,h_sum;
char char_name;
FILE*Input;
Input = fopen("Input.txt","r");
FILE*Output;
Output = fopen("Output.txt","w+");
char_name = 1; //Just using 1 as a way to make the while loop occure
while(char_name != '0')
{
fscanf(Input,"%c%f",&char_name,&amount);
switch(char_name)
{
case 'S':
printf("S,%f\n",amount);
break;
case 'G':
printf("G,%f\n",amount);
break;
case 'H':
printf("H,%f\n",amount);
break;
}
}
printf("done");
return 0;
}
(disregard the unused values, those are to be used in the actual program)
What changes would I need to make to get the loop to terminate once it reaches 0?
The following code:
fscanf(Input,"%c%f",&char_name,&amount);
will fail to read a float upon hitting the last data line in the file. The switch statement is not needed. Use an if statement to check if the first char is '0' and either break or read the floating point number and print both the character and number.
while (TRUE)
{
fscanf(Input,"%c",&char_name);
if (char_name == '0')
break;
fscanf(Input,"%f",&amount);
printf("%c,%f\n",char_name,amount);
}
Using fgets() and then parsing the line is the best way to go. But using fscanf(), recommend:
Change format so white-space is ignored. otherwise '%c' will take on white-space values
// fscanf(Input,"%c%f",&char_name,&amount);
fscanf(Input," %c%f",&char_name,&amount); // add space
Check the return value from fscanf(). do not use values char_name,amount unless the return value from fscanf() indicates those values were indeed filled.
int cnt = fscanf(Input," %c%f",&char_name,&amount);
switch(cnt) {
case 1: Handle_OnlyCharName(); break; // Candidate only "0" line
case 2: Handle_BothCharNameAndAmount(); break; // OP's switch(char_name)
case EOF: Handle_IOErrorOrEndOfFile(); break; // No more data
default: NeverShouldGetHere();
}

switch statements in while loops

I am in a chapter for control structures, i threw myself a while n case challenge but i can't seem to get it working, any heads up ?, i know my code is a bit dirty or alot dirty :D anyway the code is about asking a user for input on a color name then prints a corresponding color code, after that it asks if you want to continue if yes it continues if not it terminates.
#include <stdio.h>
main ()
{
char color[20];
char answer;
printf("Enter the color name: ");
scanf("%s", &color);
while (1) {
switch("color")
{
case "red":
printf("#FF0000\n");
break;
case "green":
printf("#00FF00\n");
break;
default:
printf("FFFFFF\n");
}
printf("Do you want to do that again(y/n): ");
scanf("%c", &answer);
if (answer == "y")
{
printf("Enter the color code: ");
scanf("%s",&color);
}
else
{
printf("Quiting.......\n");
break;
}
}
return 0;
}
There's more than one problem, but here's a few:
You're not comparing strings the right way. In C you can't use == to compare strings, you have to use strcmp (or strncmp).
You can't switch on a string in C. So you might want to replace the switch with if-else:
if (!strcmp(color, "red"))
/* ... */
else if (!strcmp(color, "green"))
/* ... */
else
/* "default" */
You're mixing different scanf strategies:
scanf("%s",&color); leaves \n in the input buffer
scanf("%c", &answer); reads that newline and stores it in answer
Basically the only good advice is: keep studying. You're not ready for this "challenge" yet.
Your switch statement always goes to default:. This is because you have the litaral "color" instead of the variable color.
You want
switch(color) {
but as pointed by others, that won't work either, because C switch doesn't allow strings.
You want to write:
switch (color)
{
...
}
but even that won't work since you need an integer expression; C does not handle string comparisons natively.
So, you'll either have to map the colour strings to integers, or forego a switch and use an `if / else if / else' chain:
if (strcmp(color, "red") == 0)
printf("#FF0000\n");
else if (strcmp(color, "green") == 0)
printf("#00FF00\n");
else
printf("FFFFFF\n");
To answer your question, you have to remember what is a string literal in C.
They are pointers to character arrays with string data embedded in the code by the compiler.
So, firstly, your switch statement uses a constant (address of "color" string) as a control variable.
Secondly, each case branch contains a meaningless address of a string as a label.
To emulate switch on strings in C, you have to use a sequence of if-else if with strcmp in conditions.

Resources