Find Word with Vowels in order C - 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

Related

Kernighan and Ritchie - exercise 3.3 (expand function)

I have solved the exercises 3.3 from the K&R book. The solution I have implemented seems to work, but is a bit verbose and there could be smarter way to write this code. I wanted to ask if there could be problems with the solution I implemented and if there were easier way to write it:
Write a function expand(s1,s2) that expands shorthand notations like
a-z in the string s1 into the equivalent complete list abc...xyz in
s2. Allow for letters of either case and digits, and be prepared to
handle cases like a-b-c and a-z0-9 and -a-z. Arrange that a leading or
trailing - is taken literally
My code is this one:
#include <stdio.h>
void expand(char s1[],char s2[]){
int j=0,i=0;
while(s1[j] != '\0'){
if (s1[j]>= 'a' && s1[j] <= 'z' && s1[j+1] == '-' && s1[j+1]!='\0' && s1[j+2] >= 'a' && s1[j+2] <= 'z' && s1[j+2] !='\0'){
int z = s1[j+2]-s1[j];
int c;
for (c=0;c<=z;c++){
s2[i]= c+s1[j];
i++;
}
j=j+3;
}
else if (s1[j]>= 'A' && s1[j] <= 'Z' && s1[j+1] == '-' && s1[j+1]!='\0' && s1[j+2] >= 'A' && s1[j+2] <= 'Z' && s1[j+2] !='\0'){
int z = s1[j+2]-s1[j];
int c;
for (c=0;c<=z;c++){
s2[i]= c+s1[j];
i++;
}
j=j+3;
}
else if (s1[j]>= '0' && s1[j] <= '9' && s1[j+1] == '-' && s1[j+1]!='\0' && s1[j+2] >= '0' && s1[j+2] <= '9' && s1[j+2] !='\0'){
int z = s1[j+2]-s1[j];
int c;
for (c=0;c<=z;c++){
s2[i]= c+s1[j];
i++;
}
j=j+3;
}
else if (j!= 0 && s1[j] == '-' && (s1[j-1] < s1[j+1])){
int z = s1[j+1]-(1+s1[j-1]);
int c;
for (c=0;c<=z;c++){
s2[i]= c+(s1[j-1]+1);
i++;
}
j=j+2;
}
else if ( s1[j]>= 32 && s1[j] <= 127 && (s1[j+1] != '-' || s1[j+1]>= 32 && s1[j+1] <= 127 )){
s2[i] = s1[j];
j++;
i++;
}
}
s2[i]='\n';
i++;
s2[i]='\0';
}
int main() {
int c;
char s2[100];
expand("-a-c,a-c-g,A-Z0-9--", s2);
printf("%s",s2);
}
The code works in this way:
First it check if there is a triplet of the kind "x-y" where x<y. Then if gives to the array the values from x to y included and jump to the next character after the triplet "x-y". The same is done for upper case letters and for numbers in further if conditions.
the condition else if (j!= 0 && s1[j] == '-' && (s1[j-1] < s1[j+1])) is used to check for cases like "a-c-d1". The code I have implemented in this example will work like this:
Since we start with the 0-th character in "a-c-d" and the pattern "x-y" is present, "abc" will be assigned to the array. then we will directly jump to the second - in "a-c-f". Since this second - is preceded by a letter "c" and followed by a letter "f", and "c"<"f", then the characters between "c" and "f" will be assigned to the array, excluding the initial "c". Then the index for the string will jump of two and reach 1.
Some other way :
you only to know the last char before - and if it is the same type as current one (lower or upper case letter or digit)
when you get a - and previous char is a letter or digit you know you may have to make expansion
if you have a letter or digit after - and it is corresponding to letter/digit before - you know you can expand from char before / to current one.
you do need to look forward but only save previous char and char before -
you do same kind of processing for each different char type (letter/digit)
You can find an example after :
#include <stdio.h>
// handle different char type
typedef enum E_chartype {
LowerCaseLetter,
UpperCaseLetter,
Digit09,
OtherChar
} E_chartype;
// save if we may have a posdible expansion
typedef enum E_states {
NothingStarted,
StartedExpansion
} E_states;
// find type of a char
E_chartype getCharType(char c) {
if ((c >= 'a') && (c <= 'z'))
return LowerCaseLetter;
if (( c >= 'A') && (c <= 'Z'))
return UpperCaseLetter;
if ((c >= '0') && (c <= '9'))
return Digit09;
return OtherChar;
}
void expandopt(char *inS, char *outS) {
// init output string to null string
outS[0] = 0;
char *endS = outS;
E_states automat = NothingStarted;
char savedChar = 0;
int currentIndex;
E_chartype prevCType=OtherChar,savedCType=OtherChar;
char savedC = 0,prevC=0;
// loop on input string
for (currentIndex = 0; inS[currentIndex] != 0;currentIndex++) {
// save current char in variable c for shorter writting
char c = inS[currentIndex];
printf("%c : ",c);
// save type of current char
E_chartype currentCType = getCharType(c);
switch (automat) {
// genersl case notjing yet started
case NothingStarted:
// possibkee expansion if previous chsr is letter or digit and current char is -
if ((prevCType != OtherChar) && (c == '-')) {
printf("start rep\n");
automat = StartedExpansion;
// save the previous char and its type as it eill br the reference fircexpansion
savedCType = prevCType;
savedC = prevC;
} else {
// reset and cooy current char to iutput
automat = NothingStarted;
printf("nothing\n");
*endS++ = c;
}
break;
case StartedExpansion:
// we make ecpansion only if still same char type and letter/digit is strictly after saved one
if ((currentCType == savedCType) && (c > savedC)){
printf("expansion ");
for (char newC
= savedC+1;newC <= c;newC++) {
*endS++ = newC;
}
// save char in case thrre id a - after, which mean nee expansion
savedC = c;
} else {
// save current chsrcsnd its type
savedCType = currentCType;
savedC = c;
// copy previous char (= -) whch was not vopief in case of expansion
*endS++ = prevC;
*endS++ = c;
}
automat = NothingStarted;
break;
}
// save current chsr and type
prevCType = currentCType;
prevC = c;
}
// add 0 at end of string
*endS = 0;
}
int main() {
expandopt("-a-c,a-c-g,A-Z0-9–",s2);
printf("%s\n",s2);
}
Sorry for the code formatting, I did not find good code editor on phone.

Make a c program that will tell if a string is a palindrome(read the same way both ways) until BYE is encountered

Everything is working in my code but as soon as user inputs "BYE" my program is not ending i don't know why while loop is not responding to that code
#include "stdio.h"
#include <string.h>
int main(void)
{
char ch[20];
while (ch != "bye")
{
scanf("%s", ch);
int i;
int n = strlen(ch);
int c = 0;
for (i = 0; i < n / 2; i++)
{
if (ch[i] == ch[n - i - 1])
c++;
}
if (c == i)
{
printf("1");
}
else
{
printf("0");
}
}
return 0;
}
For starters the array ch was not initialized that is initially it does not contain a string
char ch[20];
Secondly in the condition of the while loop
while (ch != "bye")
there are compared two addresses: the address of the first element of the array ch and the address of the first element of the string literal "bye". As the array and the string literal occupy different extents of memory the addresses always will be unequal. So as a result you have an infinite loop that does not contain a break statement.
If you want to compare strings then you need to use the standard string function strcmp as for example
if ( strcmp( ch, "bye" ) == 0 )
{
//...
}
In this case the array ch shall already contain a string.
So instead of the while statement it is better to use do-while statement or an infinite while statement that will be interrupted through the break statement if strcmp will return 0.
For example
while ( 1 )
{
char ch[20];
scanf("%19s", ch );
if ( strcmp( ch, "bye" ) == 0 ) break;
size_t n = strlen(ch);
size_t i = 0;
while ( i < n / 2 && ch[i] == ch[n - i - 1] ) ++i;
if ( i == n / 2 )
{
printf("1");
}
else
{
printf("0"); }
}
}

Not initialised and memory errors (strings and pointers)

Here is what I need to do: delete all occurrences of a number that appears most frequently in a given string
Here is what I've done: wrote two functions; the second one extracts all integers from a string into an array, finds the most frequently repeated one, calls the first function to find that number in a string, deletes all its occurrences in a given string
The problem is it works alright when I compile it, but doesn't pass the series of auto-generated tests and displays "access to an uninitialised value" and "memory error" in lines I marked with <------.
I know this is not exactly the "minimum reproducible code" but I'm hoping someone could point out what the problem is, as I run into a lot of similar errors when working with pointers.
char* find_number(char* string,int search)
{
int sign=1;
int number=0,temp=0;
char* p = string;
while(*string != '\0') {<----------
p=string;
if(*string=='-') sign=-1;
else if(*string==' ') {
string++;
continue;
} else if(*string>='0' && *string<='9') {
temp=0;
while(*string != '\0' && *string>='0' && *string<='9') {
temp=temp*10+*string-'0';
string++;
}
number=temp*sign;
if(number==search) {
return p;
}
} else {
sign=1,number=0;
}
string++;
}
return NULL;
}
char* delete_most_frequent(char* string)
{
//writing all integers in a string to an array
char* pointer=string;
char* s = string;
int temp=0, sign = 1,i=0,array[1000],number=0,counters[1001]= {0},n=0;
while (*s != '\0') {<------------
if (*s == '-') sign = -1;<----------
else if (*s >= '0' && *s <='9') {<----------
temp = 0;
while (*s != '\0' && *s >= '0' && *s <= '9') {
temp = temp * 10 + *s - '0';
s++;
}
number=sign*temp;
if(number>=0 && number<=1000) {
array[i]=number;
i++;
}
}
number=0;
sign=1;
s++;
}
n=i;//size of the array
//finding the number that occurs most frequently
int max=0;
for (i=0; i<n; i++) {
counters[array[i]]++;
if(counters[array[i]]>counters[max]) {
max=array[i];
}
}
char* p=find_number(string,max);//pointer to the first digit of wanted number
//deleting the integer
while (*string != '\0') {
if (p != NULL) {
char *beginning = p, *end = p;
while(*end>='0' && *end<='9')
end++;
//while (*beginning++ = *end++);
while(*end != '\0'){
*beginning = *end;
beginning++;
end++;
}
*beginning = '\0';
} else string++;
p=find_number(string,max);
}
return pointer;//pointer to the first character of a string
}
int main()
{
char s[] = "abc 14 0, 389aaa 14! 15 1, 153";
printf("'%s'", delete_most_frequent(s));
return 0;
}
chopping your code down to just what is likely causing the problem, you have pattern that looks like
while(*string != '\0') {
:
while(*string != '\0' ...) {
:
string++;
}
:
string++;
}
so you have two nested while loops, both of which are advancing the pointer looking for a NUL terminator to end the loop. The problem is that if the inner loop gets all the way to the NUL (it might stop earlier, but it might not), then the increment in the outer loop will increment the pointer past the NUL. It will then happily run through (probably invalid) memory looking for another NUL that might not exist. This is a hard one to catch as in most test cases you write, there are likely multiple NULs (soon) after the string, so it will appear to work fine -- you almost have to specifically write a test case to trigger this failure mode to catch this.
One fix would be to check you're not yet at the null before incrementing -- if (*string) string++; instead of just string++;

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]);
}

Scanf() function isn't taking string input

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

Resources