Scanf() function isn't taking string input - c

After taking test case inputs it does not waits for string input. I have tried fgets(); But, fgets() requires a newline from user which i think will not be accepted by online judge. So, whats the problem here ? Here is my code.
#include<stdio.h>
int main ()
{
int t, j;
int cnt = 0;
scanf("%d", &t);
while(t--)
{
cnt++;
int i, count = 0;
char s[101];
scanf("%[^\n]s", s);
for(i=0;s[i] != '\0'; i++)
{
if(s[i] == 'a' || s[i] == 'd' || s[i] == 'g' || s[i] == 'j' || s[i] == 'm' || s[i] == 'p' || s[i] == 't' || s[i] == 'w' || s[i] == ' ')
{
count += 1;
continue;
}
else if(s[i] == 'b' || s[i] == 'e' || s[i] == 'h' || s[i] == 'k' || s[i] == 'n' || s[i] == 'q' || s[i] == 'u' || s[i] == 'x')
{
count += 2;
continue;
}
else if(s[i] == 'c' || s[i] == 'f' || s[i] == 'i' || s[i] == 'l' || s[i] == 'o' || s[i] == 'r' || s[i] == 'v' || s[i] == 'y')
{
count += 3;
continue;
}
else if(s[i] == 's' || s[i] == 'z')
{
count += 4;
continue;
}
}
printf("Case #%d: %d\n", cnt, count);
}
return 0;
}

Change
scanf("%[^\n]s", s);
to
scanf(" %100[^\n]", s);
The space at the beginning makes it skip over any whitespace before the word. This is needed to allow it to read past the newline at the end of each line before scanning the next line.
100 ensures that it doesn't try to write past the end of the string.
You shouldn't have s at the end, because that will try to match a literal s in the input. [^\n] is not a modifier of the %s format operator, it's a completely different format operator.

It would help immensely if you had included a link to the specific question. Then we could advise if you had answered the question correctly.
For instance, what about capital letters, punctuation, etc.?
For instance, does the question guarantee that each input string will <= 100 characters, or is there a criteria that no more than the first 100 characters be used?
We cannot determine if the posted code is answering the question if we do not know what the question is.
Most I/O is very time/CPU cycles expensive, especially scanf() and printf()
Most online questions have the execution timed and exceeding the allowed time limit will cause the proposed answer (that you provide) to fail.
Appropriate 'fast' I/O functions are easily found by YOU by looking at the answers to prior questions. Here are a couple of fully functional examples to get you started:
#include <stdio.h>
void fastRead( size_t *a );
void fastWrite( size_t a );
inline void fastRead(size_t *a)
{
int c=0;
// note: 32 is space character
while (c<33) c=getchar_unlocked();
// initialize result value
*a=0;
// punctuation parens, etc are show stoppers
while (c>47 && c<58)
{
*a = (*a)*10 + (size_t)(c-48);
c=getchar_unlocked();
}
//printf( "%s, value: %lu\n", __func__, *a );
} // end function: fastRead
inline void fastWrite(size_t a)
{
char snum[20];
//printf( "%s, %lu\n", __func__, a );
int i=0;
do
{
// 48 is numeric character 0
snum[i++] = (char)((a%10)+(size_t)48);
a=a/10;
}while(a>0);
i=i-1; // correction for overincrement from prior 'while' loop
while(i>=0)
{
putchar_unlocked(snum[i--]);
}
putchar_unlocked('\n');
} // end function: fastWrite
Most often (you may have to experiment a bit) the online code judging wants a newline output to stdout after each test case, including the last test case. This is usually accomplished by:
putchar_unlocked('\n');
When a value will never be less than 0, it is (usually) best to use size_t rather than int,
It is good programming practice to use variable names that indicate content or usage (or better, both).
code is MUCH more readable and understandable if
it is consistently indented
code blocks are separated by a single blank line
meaningful variable names are used
all 'distractor' code is eliminated
Putting all the above together results in:
#include <stdio.h> // putchar_unlocked(), getchar_unlocked()
void fastRead( size_t *a );
void fastWrite( size_t a );
inline void fastRead(size_t *a)
{
int c=0;
// note: 32 is space character
while (c<33) c=getchar_unlocked();
// initialize result value
*a=0;
// punctuation parens, etc are show stoppers
while (c>47 && c<58)
{
*a = (*a)*10 + (size_t)(c-48);
c=getchar_unlocked();
}
//printf( "%s, value: %lu\n", __func__, *a );
} // end function: fastRead
inline void fastWrite(size_t a)
{
char snum[20];
//printf( "%s, %lu\n", __func__, a );
int i=0;
do
{
// 48 is numeric character 0
snum[i++] = (char)((a%10)+(size_t)48);
a=a/10;
}while(a>0);
i=i-1; // correction for overincrement from prior 'while' loop
while(i>=0)
{
putchar_unlocked(snum[i--]);
}
putchar_unlocked('\n');
} // end function: fastWrite
int main ( void )
{
size_t numTestCases;
fastRead( &numTestCases );
for( size_t testCase =1; testCase <= numTestCases; testCase++)
{
size_t count = 0;
int ch;
while( (ch = getchar_unlocked()) != '\n' )
{
if( ch == 'a'
|| ch == 'd'
|| ch == 'g'
|| ch == 'j'
|| ch == 'm'
|| ch == 'p'
|| ch == 't'
|| ch == 'w'
|| ch == ' ')
{
count += 1;
}
else if( ch == 'b'
|| ch == 'e'
|| ch == 'h'
|| ch == 'k'
|| ch == 'n'
|| ch == 'q'
|| ch == 'u'
|| ch == 'x')
{
count += 2;
}
else if( ch == 'c'
|| ch == 'f'
|| ch == 'i'
|| ch == 'l'
|| ch == 'o'
|| ch == 'r'
|| ch == 'v'
|| ch == 'y')
{
count += 3;
}
else if( ch == 's'
|| ch == 'z')
{
count += 4;
}
}
printf("Case #%lu: %lu\n", testCase, count);
putchar_unlocked( '\n' );
}
return 0;
}
The call to printf() could also be greatly sped up by using a series of calls to fastWrite() and putchar_unlocked()
Also, unless the question specifically asks for the superfluous characters being used in the call to printf() the code probably should say:
fastWrite( testCase );
putchar_unlocked( ' ' );
fastWrite( count );
putchar_unlocked( '\n' );
it is also highly desirable to list the parameters of the question at the top of your code. This both helps you and anyone else reading your code.
Here is a trivial example of such documentation:
/*
* criteria 1
* Using two characters: . (dot) and * (asterisk)
* print a frame-like pattern
*
* criteria 2
* You are given t - the number of test cases
*
* criteria 3
* for each of the test cases input two positive integers:
* l - the number of lines and
* c - the number of columns of a frame.
*
* criteria 4
* Use one line break in between successive patterns
*/

Given the latest information you have provided, here is the answer that I would suggest.
If it still does not pass the judge, at least you have a very solid base from which to experiment to determine the correct answer.
/*
* Cell phones have become an essential part of modern life.
* In addition to making voice calls,
* cell phones can be used to send text messages,
* which are known as SMS for short.
* Unlike computer keyboards, most cell phones have limited number of keys.
* To accommodate all alphabets, letters are compacted into single key.
* Therefore, to type certain characters,
* a key must be repeatedly pressed until that character is shown on the display
panel.
*
* In this problem we are interested in finding out the number of times
* keys on a cell phone must be pressed to type a particular message.
* In this problem we will assume that the key pad of our cell phone is arranged as follows.
* ---------------------
* |1 | abc | def |
* ---------------------
* | ghi | jkl | mno |
* ---------------------
* | pqrs | tuv | wxyz |
* ---------------------
* | | <SP>| |
* ---------------------
* In the above grid each cell represents one key.
* Here <SP> means a space.
* In order to type the letter `a', we must press that key once,
* however to type `b' the same key must be pressed twice
* and for `c' three times.
* In the same manner, one key press for `d',
* two for `e'
* and three for `f'.
* This is also applicable for the remaining keys and letters.
* Note that it takes a single press to type a space.
*
* Input
* The first line of input will be a positive integer T
* where T denotes the number of test cases.
* T lines will then follow each containing only spaces and lower case letters.
* Each line will contain at least 1 and at most 100 characters.
*
* Output
* For every case of input there will be one line of output.
* It will first contain the case number
* followed by the number of key presses required to type the message of that case.
* Look at the sample output for exact formatting.
*
* Sample Input
* 2
* welcome to ulab
* good luck and have fun
*
* Sample Output
*
* Case #1: 29
* Case #2: 41
*/
#include <stdio.h> // putchar_unlocked(), getchar_unlocked(), puts(), sprintf()
#include <string.h> // strcpy(), strcat()
#define MAX_OUTPUT_LEN 50
void fastRead( size_t *a );
void fastWrite( size_t a );
inline void fastRead(size_t *a)
{
int c=0;
// note: 32 is space character
while (c<33) c=getchar_unlocked();
// initialize result value
*a=0;
// punctuation parens, etc are show stoppers
while (c>47 && c<58)
{
*a = (*a)*10 + (size_t)(c-48);
c=getchar_unlocked();
}
//printf( "%s, value: %lu\n", __func__, *a );
} // end function: fastRead
inline void fastWrite(size_t a)
{
char snum[20];
//printf( "%s, %lu\n", __func__, a );
int i=0;
do
{
// 48 is numeric character 0
snum[i++] = (char)((a%10)+(size_t)48);
a=a/10;
}while(a>0);
i=i-1; // correction for overincrement from prior 'while' loop
while(i>=0)
{
putchar_unlocked(snum[i--]);
}
putchar_unlocked('\n');
} // end function: fastWrite
const size_t keyPressCounts[] =
{
1, 2, 3, // a b c
1, 2, 3, // d e f
1, 2, 3, // g h i
1, 2, 3, // j k l
1, 2, 3, // m n o
1, 2, 3, 4,// p q r s
1, 2, 3, // t u v
1, 2, 3, 4 // w x y z
};
int main ( void )
{
size_t numTestCases;
fastRead( &numTestCases );
for( size_t testCase =1; testCase <= numTestCases; testCase++)
{
size_t keypresses = 0;
int ch;
while( (ch = getchar_unlocked()) != '\n' )
{
if( ' ' == ch )
keypresses += 1;
else
keypresses += keyPressCounts[ ch - 'a' ];
} // end while()
char outputLine[ MAX_OUTPUT_LEN ];
strcpy( outputLine, "Case #" );
sprintf( &outputLine[ strlen(outputLine) ], "%lu", testCase );
strcat( outputLine, ": " );
sprintf( &outputLine[ strlen(outputLine) ], "%lu", keypresses );
puts( outputLine );
} // end for()
return 0;
} // end function: main

Related

why does only the 1st file reading function executes over multiple programs of the same kind in C language?

This code contains 3 file handling related functions which read from a file named "mno". But only the 1st called function in the main() is working. If the 1st function of the list is commented then, only the 2nd function will work and the third won't. Same goes for the 3rd one
#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
void countVowel(char fin[])
{
FILE *fl;
char ch;
int count = 0;
fl = fopen(fin, "r");
while (ch != EOF)
{
ch = tolower(fgetc(fl));
count += (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') ? 1 : 0;
}
fclose(fl);
printf("Number of Vowels in the file \" %s \"-> \t %d \n", fin, count);
}
void countConsonant(char fin[])
{
FILE *fl;
char ch;
int count = 0;
fl = fopen(fin, "r");
while (ch != EOF)
{
ch = tolower(fgetc(fl));
count += (!(ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') && (ch >= 'a' && ch <= 'z')) ? 1 : 0;
}
fclose(fl);
printf("Number of Consonant in the file \" %s \"-> \t %d \n", fin, count);
}
void countAlphabet(char fin[])
{
FILE *fl;
char ch;
int count = 0;
fl = fopen(fin, "r");
while (ch != EOF)
{
ch = tolower(fgetc(fl));
count += (ch >= 'a' && ch <= 'z') ? 1 : 0;
}
fclose(fl);
printf("Number of Alphabets in the file \" %s \"-> \t %d \n", fin, count);
}
int main()
{
countVowel("mno"); // output -> 10
countConsonant("mno"); // output -> 0
countAlphabet("mno"); // output -> 0
return 0;
}
Here are the contents of "mno" file ->
qwertyuiopasdfghjklzxcvbnm, QWERTYUIOPASDFGHJKLZXCVBNM, 1234567890
As others have mentioned, your handling of EOF was incorrect:
ch was uninitialized on the first loop iteration
Doing tolower(fgetc(fl)) would obliterate the EOF value.
Using char ch; instead of int ch; would allow a [legitimate] 0xFF to be seen as an EOF.
But, it seems wasteful to have three separate functions to create the three different counts because the most time is spent in the I/O versus the determination of what type of character we're looking at. This is particularly true when the counts are so interelated.
We can keep track of multiple types of counts easily using a struct.
Here's a refactored version that calculates all three counts in a single pass through the file:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
struct counts {
int vowels;
int consonants;
int alpha;
};
void
countAll(const char *fin,struct counts *count)
{
FILE *fl;
int ch;
int vowel;
count->vowels = 0;
count->consonants = 0;
count->alpha = 0;
fl = fopen(fin, "r");
if (fl == NULL) {
perror(fin);
exit(1);
}
while (1) {
ch = fgetc(fl);
// stop on EOF
if (ch == EOF)
break;
// we only care about alphabetic chars
if (! isalpha(ch))
continue;
// got one more ...
count->alpha += 1;
ch = tolower(ch);
// is current character a vowel?
vowel = (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u');
// since we know it's alphabetic, it _must_ be either a vowel or a
// consonant
if (vowel)
count->vowels += 1;
else
count->consonants += 1;
}
fclose(fl);
printf("In the file: \"%s\"\n",fin);
printf(" Number of Vowels: %d\n",count->vowels);
printf(" Number of Consonants: %d\n",count->consonants);
printf(" Number of Alphabetics: %d\n",count->alpha);
}
int
main(void)
{
struct counts count;
countAll("mno",&count);
return 0;
}
For your given input file, the program output is:
In the file: "mno"
Number of Vowels: 10
Number of Consonants: 42
Number of Alphabetics: 52
You are using ch uninitialized. at while (ch != EOF). Every function call after the first has ch equal to 0 at the start, because you forgot to initialize it and the memory was set to -1 before. You can fix it by replacing the loops like this:
int ch;
...
while ((ch = fgetc(fl)) != EOF)
{
ch = tolower(ch);
count += ...;
}
Here ch is getting initialized before you check it and later converted to lowercase.
EDIT:
Note that this only works if ch is an int, so it can handle the value of -1 (EOF) and the byte 255 is not truncated to -1.
EDIT:
At first I said ch was 0 all the time. It was -1. I am so sorry, I swapped it with the null terminator, which is usually the reason for such behavior.

Number of occurences of any two specific letters in a line or text( string)

Q : Write a program to count the number of occurrences of any two vowels in succession in a line of text. For example the following sentence :
"Please read the application and give me gratuity"
Such occurrences in the sentence are :- "ea" , "ea" , "io" , "ui". Ultimately the question is to count the number of such occerrences in the line which is a user input string.
Problem : My program is just recieve a line but did not give any output.
It's my first question in stackoverflow. I am a beginner in programming.
My code:
# include <stdio.h>
int main () {
char line[100];
printf("\nEnter a line\n");
gets(line);
//printf("You entered : %s\n", line);
char A,E,I,O,U,a,e,J,o,u;
A = 'A';
E = 'E';
I = 'I';
O = 'O';
U = 'U';
a = 'a';
e = 'e';
J = 'i';
o = 'o';
u = 'u';
int occurence =0,i =0 ;
while (line[i] =! '\0'){
if((line[i] == A || E || I || O || U || a || e || J || o || u) && (line[i+1] == a || e || J || o || u)){
occurence++;
}
i++;
}
printf("Number of occurence of any two vowels in succession in the line is : %d\n", occurence);
return 0;
}
Your code has multiple issues, some of which are:
You use gets to read the string. This function is now at least deprecated (I think it was even removed from recent versions of the standard library) because it is unsafe. Use fgets instead!
You use the || operator wrong - this was already pointed out in mediocrevegetable1's comment.
You could use a code similar to this one to solve your problem. The code contains comments, so it should be easy to understand. However, if this is a homework or project for school, do NOT use this exact code, as this would most likely be considered plagiarism!
#include <stdio.h>
#include <ctype.h>
#define STRLEN 100
int main () {
char line[STRLEN];
char* ch;
char incrementIfVowel;
int occurences;
/* Read line */
printf("\nEnter a line\n");
fgets(line, STRLEN, stdin);
/* Init variables */
incrementIfVowel = 0;
occurences = 0;
/* Iterate through characters */
for (ch = line; *ch != '\0'; ch++) {
/* Test if the current character is a vowel. Three cases can occur: */
if (toupper(*ch) == 'A' || toupper(*ch) == 'E' || toupper(*ch) == 'I' || toupper(*ch) == 'O' || toupper(*ch) == 'U') {
if (incrementIfVowel == 1) {
/* Case 1: The current character is a vowel, and its predecessor was also a vowel */
incrementIfVowel = 0;
occurences++;
}
else {
/* Case 2: The current character is a vowel, but its predecessor was not a vowel or it was the second vowel in a row */
incrementIfVowel = 1;
}
}
else {
/* Case 3: The current character is not a vowel */
incrementIfVowel = 0;
}
}
/* Print result */
printf("Number of occurence of any two vowels in succession in the line is : %d\n", occurences);
return 0;
}
There are 3 main issues with your code:
gets(line);
gets doesn't check the length of the buffer and for this reason, is susceptible to buffer overflows. gets had been deprecated since C99 and was removed in C11. You're probably compiling with an older version of the standard; I'd suggest you switch to newer versions. As for an alternative, see fgets.
while (line[i] =! '\0'){
=! is a typo. Replace it with !=
if((line[i] == A || E || I || O || U || a || e || J || o || u) && (line[i+1] == a || e || J || o || u))
This will always evaluate to true because || doesn't chain like that. Ideally, you should put this in a function:
_Bool is_vowel(char ch)
{
return toupper(ch) == 'A' || toupper(ch) == 'E' || toupper(ch) == 'I' || toupper(ch) == 'O' || toupper(ch) == 'U';
}
toupper is defined in <ctype.h> so be sure to include that. You could also shorten this behemoth of a line with return strchr("AEIOUaeiou", ch), but if you haven't used strchr and are not comfortable with using it yet, that's okay.
Modifying only the incorrect parts, your final code will can look something like this:
#include <stdio.h>
#include <ctype.h>
_Bool is_vowel(char ch)
{
return toupper(ch) == 'A' || toupper(ch) == 'E' || toupper(ch) == 'I' || toupper(ch) == 'O' || toupper(ch) == 'U';
}
int main () {
char line[100];
printf("\nEnter a line\n");
fgets(line, sizeof line, stdin);
int occurence = 0, i = 0;
while (line[i] != '\0') {
if(is_vowel(line[i]) && is_vowel(line[i + 1]))
occurence++;
i++;
}
printf("Number of occurence of any two vowels in succession in the line is : %d\n", occurence);
return 0;
}
An example of running this:
Enter a line
Please do something about the bee hive and then eat some meat
Number of occurence of any two vowels in succession in the line is : 5
(5 because Pl<ea>se do something ab<ou>t the b<ee> hive and then <ea>t some m<ea>t)

C: Printing from char array produces erroneous characters

Solutions for K. N. King's C Programming: A Modern Approach, 2nd Edition, Chapter 8, Programming Project 14, produces different outputs both correct and incorrect. Examples shown below:
Reversal of sentence: you can't swallow a cage can you?
Reversal of sentence: you can't swallow a cage can you�(�?
Reversal of sentence: you can't swallow a cage can you��x�?
Reversal of sentence: you can't swallow a cage can you�Ց�?
As shown by the example input, correct output should be:
Enter a sentence: you can cage a swallow can't you?
Reversal of sentence: you can't swallow a cage can you?
My own solution and below solution (courtesy of Github user #williamgherman; slightly modified for sake of readability) both produces the different outputs.
#include <stdio.h>
int main(void)
{
char ch, terminator, sentence[100] = {0};
int i = 0, j;
printf("Enter a sentence: ");
for (i = 0; (ch = getchar()) != '\n' && i < 100; i++) {
if (ch == '.' || ch == '!' || ch == '?') {
terminator = ch;
break;
}
sentence[i] = ch;
}
printf("Reversal of sentence: ");
while (i >= 0) {
while (sentence[--i] != ' ' && i != 0)
;
j = i == 0 ? 0 : i + 1;
while (sentence[j] != ' ' && sentence[j] != '\0')
putchar(sentence[j++]);
if (i > 0)
putchar(' ');
}
printf("%c\n", terminator);
return 0;
}
Despite double checking the code, and running through the example input on paper, I've not been able to find an answer.
How come the code produces these different outputs, correct as well as incorrect? What produces the erroneous characters?
Most likely, the problem is with the exit condition for the while loop used to print the sentence in reverse
while (i >= 0) {
while (sentence[--i] != ' ' && i != 0) ;
....
Consider the case where the code is going to print the first word (i=3):
The second while will decrement i all the way to 0
then the code will print the word 'you' (positions 0 to 2, inclusive)
At this point i=0, the first while still is true
The second while will decrement i to -1, and will continue to decrement it to -2, -3, until a space is found.
The code will print the word with indices of -1, -2, -3, and will print a string based on those undefined values.
Yes, as stated in the answer above the problem is within this block
while (i >= 0) {
while (sentence[--i] != ' ' && i != 0) ;
....
You should change the i != 0 part into i >= 0, this should solve the thing
The problem is that i decrementation sentence[--i] happens before i != 0 and so imagine the while loop starting with i = 0 - this will mean that sentence[i - 1] will (likely) not be ' ' and i will not be equal to zero.
For starters the program has undefined behavior because the variable terminator is not initialized. The user can press the Enter key without supplying one of these characters ".!?"
for (i = 0; (ch = getchar()) != '\n' && i < 100; i++) {
^^^^^^^
In this case this statement
printf("%c\n", terminator);
will output an indeterminate value.
Moreover the user can interrupt the loop pressing a corresponding key combination but the loop does not process such a situation.
If the user pressed the Enter key in the very beginning of the loop then i will be equal to 0 In this case the inner while loop
while (i >= 0) {
while (sentence[--i] != ' ' && i != 0)
^^^
;
will invoke undefined behavior.
Moreover before the terminating character (".!?") the sentence can contain spaces. Thus this loop
while (sentence[--i] != ' ' && i != 0)
;
j = i == 0 ? 0 : i + 1;
again will be incorrectly terminated. That is j will be equal to i + 1 where a zero character is stored (provided that the user did not entered all 100 elements of the array sentence).
Apart from this the program does not output existent number of spaces between words. It only tries to output one space
putchar(' ');
Take into account that the user can enter for example the tab character '\t' instead of the space character ' '.
Below there is shown how the program can be written.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main(void)
{
const char *punctuation = ".?!";
enum { N = 100 };
char s[N] = "";
char terminator = '\0';
printf( "Enter a sentence: " );
size_t n = 0;
for ( int c; n < N && ( c = getchar() ) != EOF && c != '\n'; n++ )
{
if ( strchr( punctuation, c ) )
{
terminator = c;
break;
}
s[n] = c;
}
printf( "Reversal of sentence: " );
putchar( '\"' );
size_t i = 0;
while ( i != n && isblank( ( unsigned char )s[i] ) ) putchar( s[i++] );
for ( size_t j = n; i != n; )
{
while ( i != n && !isblank( ( unsigned char )s[i] ) ) i++;
while ( isblank( ( unsigned char )s[j-1] ) ) j--;
size_t k = j;
while ( j != 0 && !isblank( ( unsigned char )s[j-1] ) ) j--;
for ( size_t l = j; l != k; l++ ) putchar( s[l] );
while ( i != n && isblank( ( unsigned char )s[i] ) ) putchar( s[i++] );
}
if ( terminator ) putchar( terminator );
putchar( '\"' );
return 0;
}
The program output might look like
Enter a sentence: you can cage a swallow can't you?
Reversal of sentence: "you can't swallow a cage can you?"
As you can see the program preserved all spaces contained in the entered sentence.

Program to find vowels, If statements not assigning correct values [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 3 years ago.
Improve this question
I have a simple program to find the vowels in a string. The for loop is supposed to iterate through the string and see if the char matches any of the vowels using and if else block but the output is just 100 As.
I tried making them all just ifs but that gave all Us.
#include <stdio.h>
int main()
{
const int SIZE = 100;
char str[SIZE] = {"the brown fox\0"};
char vowels[SIZE];
for (int i = 0; i <= SIZE; i++) {
if (str[i] == '97' || '65') {
vowels[i] = 'a';
}
else if (str[i] == '101' || '69' ) {
vowels[i] = 'e';
}
else if (str[i] == '105' || '73') {
vowels[i] = 'i';
}
else if (str[i] == '111' || '81') {
vowels[i] = 'o';
}
else if (str[i] == '117' || '85') {
vowels[i] = 'u';
}
printf("%c", vowels[i]);
}
return 0;
}
EDIT: Fixed the assignment if e.g. (str[i] == '97' || str[i] == '65') now it's printing strange symbols
EDIT 2: New code
#include <stdio.h>
int main()
{
const int SIZE = 100;
char str[SIZE] = {"the brown fox\0"};
char vowels[SIZE];
for (int i = 0; i <= SIZE; i++) {
if (str[i] == 'a' || str[i] == 'A') {
vowels[i] = 'a';
}
else if (str[i] == 'e' || str[i] =='E' ) {
vowels[i] = 'e';
}
else if (str[i] == 'i' || str[i] == 'I') {
vowels[i] = 'i';
}
else if (str[i] == 'O' || str[i] == 'o') {
vowels[i] = 'o';
}
else if (str[i] == 'u' || str[i] == 'U') {
vowels[i] = 'u';
}
printf("%c", vowels[i]);
}
return 0;
}
EDIT 3: Even after initialing vowels to '' at the start of the loop as suggested the strange symbols are gone but it's still not functioning properly.
You are comparing your char str[i] with '97'
6.4.4.4
An integer character constant has type int. The value of an integer character constant containing a single character that maps to a single-byte execution character is the numerical value of the representation of the mapped character interpreted as an integer. The value of an integer character constant containing more than one character (e.g., 'ab'), or containing a character or escape sequence that does not map to a single-byte execution character, is implementation-defined.
If you want to compare a char you can use the ascii value for example 97 or directly the char with 'c'.
For more maintenability and readability I prefer using the char directly.
There is other problems in your code:
First, in your for loop: for (int i = 0; i <= SIZE; i++) {
You are going too far in your array because of your <= as arrays id starts with 0, if you type str[100], in reality you are using the 101st char.
Another problem is your if statements: if (str[i] == '97' || '65') {
Here your if statement is equivalent to if (str[i] == '97' || '65' != 0) {
Consider retyping str[i] == : if (str[i] == '97' || str[i] == '65') {
Plus don't forget the first problem I mentionned about your '97'
You have a very large number of small problems summarized below:
#define SIZE 100 /* if you need a constant, #define one (or more) */
...
char vowels[SIZE] = ""; /* initialize all zero, {0) is valid also */
An integer constant is created by #define or by use of an enum. A const qualified int is not a constant integer. (that said VLAs are legal in C99, but optional in C11)
int idx = 0; /* separate index for filling vowels array */
Keep a separate index for filling the vowels array.
/* don't use magic-numbers in your code */
if (str[i] == 'a' || str[i] == 'A') {
Don't use magic-numbers, instead, use literal character constants were needed in your code to produce much more readable code.
Your program takes arguments, use them to pass the string to parse (or read from stdin), e.g.
int main (int argc, char **argv) {
const char *str = (argc > 1) ? argv[1] : "the brown fox";
...
The test ? if_true : if_false operator is called the ternary operator. It allows a simple in-line conditional to select one of two values based on the test condition (e.g. (argc > 1))
If you plan on using vowels as a string, don't forget to nul-terminate vowels after the loop, e.g.
vowels[idx] = 0; /* nul-terminate vowels */
Correcting all the errors and adding the arguments to main() you could do something similar to:
#include <stdio.h>
#define SIZE 100 /* if you need a constant, #define one (or more) */
int main (int argc, char **argv) {
const char *str = (argc > 1) ? argv[1] : "the brown fox";
char vowels[SIZE] = ""; /* initialize all zero, {0) is valid also */
size_t idx = 0; /* separate index for filling vowels array */
for (int i = 0; idx < SIZE - 1 && str[i]; i++) {
/* don't use magic-numbers in your code */
if (str[i] == 'a' || str[i] == 'A') {
vowels[idx++] = 'a'; /* assign 'a', increment index */
}
else if (str[i] == 'e' || str[i] == 'E' ) {
vowels[idx++] = 'e';
}
else if (str[i] == 'i' || str[i] == 'I') {
vowels[idx++] = 'i';
}
else if (str[i] == 'o' || str[i] == 'O') {
vowels[idx++] = 'o';
}
else if (str[i] == 'u' || str[i] == 'U') {
vowels[idx++] = 'u';
}
}
vowels[idx] = 0; /* nul-terminate vowels */
printf (" %zu vowels: ", idx); /* print number of vowels */
for (int i = 0; vowels[i]; i++) /* output each vowel, comma-separated */
printf (i > 0 ? ", %c" : "%c", vowels[i]);
putchar ('\n'); /* tidy up with newline */
return 0;
}
Example Use/Output
bin\vowels.exe "a quick brown fox jumps over the lazy dog"
11 vowels: a, u, i, o, o, u, o, e, e, a, o
Depending on your compiler str[i] == '117' (and the rest) may give you an error as signle quotes are only to be used when you want to implement the ascii equivalent of a single character like 'a' or so. Therefore str[i] == '117' is checking if str[i] is equal to the ascii equivalent of "117".
Other than that " || " is a logical "or" operator. When you write down str[i] == '111' || '81' you simply mean "find ascii codes of 111 and 81(which dont exist) , use them in "or" operation, check if the result equals str[i]".
last but not least i found a nice function online which might help making your code more compact
int isvowel(int ch)
{
int c = toupper(ch);
return (c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U');
}
to explain it shortly, if the char equivalent of given int ch is lowercase, the function changes it to uppercase and checks if it is an uppercase vowel, if the given integer already equals an uppercase vowel int c = toupper(ch); doesnt change anything.
Implementation can be done as:
for(int i=0; i<SIZE; i++) //scan all emelents of str[SIZE]
{
if(isvowel(str[i])) //print if vowel
printf ("%c", str[i]);
}

Find Word with Vowels in order C

So for a lab at uni... Ive been challenged to find all words in the usr/share/dict/linux.words
file using fopen, fgets etc with every vowel only once, in order.
i.e. facetious
So far I have the following code... but its flawed somewhere...
int all_vowels( char *s )
{
const unsigned char *p = (const unsigned char *)s;
char *v = malloc(sizeof(char *));
char *vowel = v;
if(*p == '\0') return -1;
while( *p != '\0' )
{
if( *p == 'a' || *p =='e' || *p =='i'|| *p =='o' || *p =='u' )
{
*v = *p;
v++;
}
p++;
}
if ( *vowel == 'a' && (*vowel + 1) == 'e' && (*vowel + 2) == 'i' && (*vowel + 3) == 'o' && (*vowel + 4) == 'u' )
{
return 1;
}
return -1;
}
int main (int argc, char *argv[])
{
FILE *file;
char line[BUFSIZ];
if (( file = fopen("/usr/share/dict/words", "r") ) == NULL)
{
fprintf(stderr, "cannot open %s\n", "/usr/share/dict/words");
exit(1);
}
while ( !feof(file) )
{
fgets(line, sizeof(line), file);
if ( all_vowels(line) == 1 )
{
printf("%s\n", line);
}
}
fclose(file);
return 0;
}
Any tips would be great!!!
Im really confused at the moment...
You are accessing v as if it were pointing to a location holding a number of characters, when indeed you only reserve space for one single char * (usually 4 byte on a 32 bit machine and 8 byte on a 64 bit machine):
char *v = malloc(sizeof(char *));
That might or might not be enough for what you are trying to store in it; in your case, the number of vowels, in any given word.
Whenever possible, you should avoid dynamic allocations; in your case, you don't need them, you can declare an array of fixed size instead of a char*:
char v[5];
In addition to that, you have to check if you have read 5 vowels already, so that you don't exceed the array size; if, after 5 vowels, you encounter another one, you can stop the check anyway; the currently encountered one has to be a duplicate vowel, the word will therefore not qualify.
The way you address characters is also a problem. Check again what * does: it dereferences the expression immediately to the right. In your case, it will always dereference v, then add something to it (which is also legal, since the result of dereferencing is a char). So if the first character where v points to is an a, the second an e, then *v will yield 'a', (*v + 1) will yield 'b', (*v +2) will yield 'c' and so on - you see, the result is an addition to the letter a by the given number; it doesn't matter at all what comes after the first character because you never access the value there. To achieve what you want with pointer arithmetic, you'd have to use parenthesis: *(v+1) - i.e., add 1 to the pointer v, then dereference it. This would yield the second character in the c string starting at v, i.e. 'e'.
Note that with v declared as above you can simply write v[0], v[1], v[2] and so on to address each character.
Aside from that, check the last comparison in your if condition, you had an 'e' instead of an 'u' there.
By the way, as a side note, and something to think about: There is a solution to your problem which does not require the v/vowel variables at all... only a single integer variable!
but its flawed somewhere...
Could there be an error here?
if ( *vowel == 'a' &&
(*vowel + 1) == 'e' &&
(*vowel + 2) == 'i' &&
(*vowel + 3) == 'o' &&
(*vowel + 4) == 'e' )
// ^^^ 'u'?
There may also be other errors. I haven't checked all your code.
Here is a big flaw:
char *v = malloc(sizeof(char *));
This only allocates four or eight bytes (depending on if you are on a 32 or 64 bit platform). I'm guessing you want a little more than that.
PS. In the future, you should probably try to be more specific instead of just saying that "it's flawed".
Why is all_vowels() allocating memory? And, even more interesting, why doesn't it free() it?
I'm pretty sure all_vowels() doesn't have to allocate any memory, and can be a bit simpler than what you have.
Also, you can´t use feof() before trying to read from the file. Remove that, just loop until fgets() returns NULL.
I would probably write a helper function int is_vowel(char c); to make the code clearer, and then attack the problem like so in all_vowels():
vowels = "aeiou"
for each character x in the string to check:
if is_vowel(x):
if vowels starts with x:
let vowels = vowels[1:]
else
return false
return true if vowels is empty
Okay.. So I finally got the right output... Any hints or tips for greater efficiency would be much appreciated.
int all_vowels( char *s )
{
const unsigned char *p = (const unsigned char *)s;
char v[5];
int i = 0;
if(*p == '\0') return -1;
while( *p != '\0' )
{
if( (*p == 'a' || *p =='e' || *p =='i'|| *p =='o' || *p =='u') && ( i < 5 ) )
{
v[i] = *p;
i++;
}
p++;
}
if ( ( v[0] == 'a' && v[1] == 'e' && v[2] == 'i' && v[3] == 'o' && v[4] == 'u' ) && (strlen(v) == 5 ))
{
return 1;
}
return -1;
}
int main (int argc, char *argv[])
{
FILE *file;
char line[30];
if (( file = fopen("/usr/share/dict/words", "r") ) == NULL)
{
fprintf(stderr, "cannot open %s\n", "/usr/share/dict/words");
exit(1);
}
while ( fgets(line, sizeof(line), file) )
{
if ( all_vowels(line) == 1 )
{
printf("%s\n", line);
}
}
fclose(file);
return 0;
}
little unsure regarding parseing your file yet i function(s) below check that a character is a vowel and tests whether the next vowel is greater then the current vowel.
#include <stdio.h>
// for readability not advocating the
// usage of #define booleans etc
#define TRUE 1
#define FALSE 0
int isVowel (char c)
{
switch (c)
{
case 'a': return TRUE;
case 'e': return TRUE;
case 'i': return TRUE;
case 'o': return TRUE;
case 'u': return TRUE;
case 'A': return TRUE;
case 'E': return TRUE;
case 'I': return TRUE;
case 'O': return TRUE;
case 'U': return TRUE;
}
return FALSE;
}
int hasOrderedVowels (char *str)
{
char c1, c2;
c1 = *str;
c2 = *(++str);
// ignore words beginning in vowels other then 'a' or 'A'
if (isVowel(c1) && !(c1 == 'a' || c1 == 'A')) return FALSE;
do {
// ignore case of `c1`
if (c1 >= 'a')
c1 -= 32;
// ignore case of `c2`
if (c2 >= 'a')
c2 -= 32;
// compare vowels and increment
// pointers as appropriate
if (isVowel(c1) && isVowel(c2))
{
// if we have found a vowel less then or equal to current
// then they are not in order/more then one, if we have found
// a 'U' and there are more vowels then this would be a duplicate
if (c2 <= c1 || c1 == 'U')
return FALSE;
c1 = c2;
}
else if (isVowel(c2)) // found first vowel so assign to c1
{
if (!(c1 == 'a' || c1 == 'A'))
{
return FALSE;
}
c1 = c2;
}
else if (!isVowel(c1))
{
c1 = *(str += 2); // skip over c2
}
c2 = *(++str);
}
while (c2 != '\0');
return (c1 == 'U');
}
int main ()
{
char *str[] = {"aeiou", "facecious", "chimpanze", "baboon"};
int i = 0;
for (; i<5; i++)
{
printf ("%s: %i\n", str[i], hasOrderedVowels(str[i]));
}
return 0;
}
demo

Resources