I am trying to solve one problem from spoj http://www.spoj.com/problems/ARITH2/
But every time i am getting 'WA' Wrong Answer.I've tried every possible Test Case and it's giving me expected results.I've written the code mentioned below:
#include <stdio.h>
int main() {
int t,s=0;char operator;
scanf("%d",&t);
while(t--)
{
signed long long int s=0,c=0;
scanf("%lld",&s);
while(1)
{
operator=0;
operator=getc(stdin);
if(operator=='=')
break;
scanf("%lld",&c);
switch(operator)
{
case '+' : s=s+c;
break;
case '-' : s=s-c;
break;
case '*' : s=s*c;
break;
case '/' : s=s/c;
break;
}
}
printf("%lld\n",s);
}
return 0;
}
Please check the requirement, you should not use scanf instead, using sscanf cos the input is whole expression such 50 * 40 * 250 + 791 =. You can create a simple parser as below code to walkthrough whole expression.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
char ch = 0;
int state = 0;
char buff[128];
char ops = 0;
unsigned int result = 0;
int i = 0, idx = 0;
char expr[1024];
int cnt = 0;
if (scanf("%[^=]=%n", expr, &cnt) <= 0)
return 0;
while(idx < cnt) {
ch = expr[idx++];
printf("state %d ch %c\n", state, ch);
switch(state) {
case 0:
if ((ch <= '9') && (ch >= '0')) {
state++;
buff[i++] = ch;
}
break;
case 1:
if ((ch <= '9') && (ch >= '0')) {
buff[i++] = ch;
} else {
buff[i] = '\0';
if (i > 0) {
unsigned int num = atoi(buff);
switch (ops) {
case '-':
result -= num;
break;
case '+':
result += num;
break;
case '*':
result *= num;
break;
case '/':
result /= num;
break;
default:
result = num;
break;
}
printf("> found fact %d, result %u\n", num, result);
}
i = 0;
if ((ch == '-') || (ch == '+') || (ch == '*') || (ch == '/')) {
state = 0;
ops = ch;
printf("> found ops %c\n", ch);
} else if ((ch == ' ') || (ch == '\t')) {
continue;
} else if (ch == '=') {
break;
} else {
// expression end
break;
}
}
break;
default:
break;
}
}
printf("> result '%u' ", result);
return 0;
}
Quick glance, it doesn't look like you are respecting the spacing outlined in the spec. For example, 1 + 1 * 2 = is going to read the wrong character for operator. 1+1*2= looks like it'll work, but that's not what was asked for.
Also, you're reading in unsigned integers and will instantly fail any test cases with signed numbers.
Related
I was trying to write a code to convert infix expression into postfix expression , I have the source code here and when I compile and give the input say 'a+b' it returns 'ab?' as the answer it does not show the operator symbols at all. Can you guys please tell me where I have gone wrong.!!
It also shows this warning when I compile
infpos.c:74:1: warning: non-void function does not return a value in all control paths [-Wreturn-type]
PS: I got to know what is the error.. Thank you
(The error was in the line 58 I had to use prefix increment but I had used postfix increment)
#include<stdio.h>
#include<ctype.h>
#define max 30
void main()
{
char inf[30],post[30];
void convert(char [],char []);
printf("Enter the infix exxpression\n");
scanf("%s",inf);
convert(inf,post);
printf("Postfix expression is\n");
printf("%s\n",post);
}
void convert(char inf[],char post[])
{
int i,j=0,top=-1,f=1,test;
char stack[30],ch,x;
int check(char);
int pre(char);
for(i=0;inf[i]!='\0';i++)
{
ch = inf[i];
test = check(ch);
switch(test)
{
case 1:
post[j++] = ch;
break;
case 2:
stack[++top] = ch;
break;
case 3:
while((x=stack[top--])!='(')
post[j++] = x;
break;
case 4:
do
{
if(top==-1)
f = 1;
else if(stack[top] == '(')
f = 1;
else if(pre(ch)>pre(stack[top]))
f = 1;
else
{
post[j++] = stack[top--];
f = 0;
}
}while(f==0);
stack[top++] = ch;
break;
}
}
while(top!=-1)
post[j++] = stack[top--];
post[j] = '\0';
}
int pre(char op)
{
if(op == '+' || op=='-')
return 1;
else if(op == '/' || op=='*' || op =='%')
return 2;
else if(op=='^')
return 3;
}
int check(char ch)
{
if(isalnum(ch))
return 1;
else if(ch=='(')
return 2;
else if(ch == ')')
return 3;
else if(ch == '+' || ch =='-' || ch=='/' || ch =='*' || ch=='%' || ch=='^')
return 4;
else
return 5;
}
I've encountered an issue with heap deallocation using free() in my tokenizer. The tokenizer is part of a recursive descent parsing calculator, which works flawlessly otherwise. But upon incorporation of a call to the deallocation function, it behaves erratically. While realistically, the calculator will likely never come close to exhausting its heap, writing a program with a memory leak is just poor practice.
tokenize.h
#define OPERAND 0
#define OPERATOR 1
#define PARENTHESIS 2
#define TERMINAL 3
#define ADD '+'
#define SUBTRACT '-'
#define MULTIPLY '*'
#define DIVIDE '/'
#define EXPONENT '^'
#define L_PARENTHESIS '('
#define R_PARENTHESIS ')'
typedef struct {
int id;
char *value;
} token;
int token_count();
token *tokenize();
void deallocate();
tokenize.c
#include <stdio.h>
#include <stdlib.h>
#include "tokenize.h"
int token_count(char string[]) {
int i = 0;
int count = 0;
while (string[i] != '\0') {
if (string[i] >= '0' && string[i] <= '9') {
while (1) {
i++;
if (string[i] >= '0' && string[i] <= '9') {
continue;
} else {
break;
}
}
count++;
continue;
}
switch (string[i]) {
case ADD:
case SUBTRACT:
case MULTIPLY:
case DIVIDE:
case EXPONENT:
case L_PARENTHESIS:
case R_PARENTHESIS:
count++;
i++;
continue;
default:
return 0;
break;
}
}
return count;
}
token *tokenize(char string[]) {
int i = 0;
token *ret;
int count = token_count(string);
if (!count) {
return ret;
}
ret = malloc((count + 1) * sizeof(token));
ret[count].id = TERMINAL;
int ret_ind = 0;
while (string[i] != '\0') {
if (string[i] >= '0' && string[i] <= '9') {
ret[ret_ind].id = OPERAND;
int size = 0;
int j = i;
while (1) {
size++;
j++;
if (string[j] >= '0' && string[j] <= '9') {
continue;
} else {
break;
}
}
ret[ret_ind].value = malloc(size * sizeof(char) + 1);
ret[ret_ind].value[size + 1] = '\0';
for(int k = 0; k < size; k++) {
ret[ret_ind].value[k] = string[i + k];
}
i = j;
ret_ind++;
continue;
}
switch (string[i]) {
case ADD:
case SUBTRACT:
case MULTIPLY:
case DIVIDE:
case EXPONENT:
ret[ret_ind].id = OPERATOR;
ret[ret_ind].value = malloc(2 * sizeof(char));
ret[ret_ind].value[0] = string[i];
ret[ret_ind].value[1] = '\0';
ret_ind++;
i++;
continue;
case L_PARENTHESIS:
ret[ret_ind].id = PARENTHESIS;
ret[ret_ind].value = malloc(2 * sizeof(char));
ret[ret_ind].value[0] = L_PARENTHESIS;
ret[ret_ind].value[1] = '\0';
ret_ind++;
i++;
continue;
case R_PARENTHESIS:
ret[ret_ind].id = PARENTHESIS;
ret[ret_ind].value = malloc(2 * sizeof(char));
ret[ret_ind].value[0] = R_PARENTHESIS;
ret[ret_ind].value[1] = '\0';
ret_ind++;
i++;
continue;
default:
break;
}
break;
}
return ret;
}
void deallocate(token *in) {
int i = 0;
while (1) {
free(in[i].value);
i++;
if (in[i].id == TERMINAL) {
break;
}
}
free(in);
return;
}
There are multiple problems in your code:
in case the input line has no tokens or a syntax error, you return ret uninitialized from tokenize. You should return NULL instead.
ret[ret_ind].value[size + 1] = '\0'; stores the null terminator one step too far in the allocated array. It should be ret[ret_ind].value[size] = '\0';
malloc(size * sizeof(char) + 1) is inconsistent: if you insist on using sizeof(char), which is 1 by definition, you should write malloc((size + 1) * sizeof(char)), but it is idiomatic to use malloc(size + 1) in C and you could also replace multiple lines of code with a simple ret[ret_ind].value = strndup(string + i, k);
the cases for L_PARENTHESIS and R_PARENTHESIS could be merged into a single block.
the deallocation loop should stop when you reach the TERMINAL token. As currently coded, you cannot handle an empty list, which you should not produce, but it is better to make utility functions more resilient to later changes.
void deallocate(token *in) {
if (in) {
for (int i = 0; in[i] != TERMINAL; i++)
free(in[i].value);
free(in);
}
}
the prototypes in token.h should include the typed argument lists.
Here is a simplified version:
#include <stdio.h>
#include <stdlib.h>
#include "tokenize.h"
int token_count(const char *string) {
int count = 0;
int i = 0;
while (string[i] != '\0') {
switch (string[i++]) {
case ' ':
continue;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
i += strspn(string + i, "0123456789");
continue;
case ADD:
case SUBTRACT:
case MULTIPLY:
case DIVIDE:
case EXPONENT:
case L_PARENTHESIS:
case R_PARENTHESIS:
count++;
continue;
default:
return -1;
}
}
return count;
}
token *tokenize(const char *string) {
int count = token_count(string);
if (count <= 0)
return NULL;
token *ret = malloc((count + 1) * sizeof(token));
int i = 0;
int ret_ind = 0;
while (string[i] != '\0') {
if (string[i] >= '0' && string[i] <= '9') {
int size = strspn(string + i, "0123456789");
ret[ret_ind].id = OPERAND;
ret[ret_ind].value = strndup(string + i, size);
ret_ind++;
i += size;
continue;
}
switch (string[i]) {
case ' ':
i++;
continue;
case ADD:
case SUBTRACT:
case MULTIPLY:
case DIVIDE:
case EXPONENT:
ret[ret_ind].id = OPERATOR;
ret[ret_ind].value = malloc(2);
ret[ret_ind].value[0] = string[i];
ret[ret_ind].value[1] = '\0';
ret_ind++;
i++;
continue;
case L_PARENTHESIS:
case R_PARENTHESIS:
ret[ret_ind].id = PARENTHESIS;
ret[ret_ind].value = malloc(2);
ret[ret_ind].value[0] = string[i];
ret[ret_ind].value[1] = '\0';
ret_ind++;
i++;
continue;
default:
break;
}
break;
}
ret[ret_ind].id = TERMINAL;
return ret;
}
void deallocate(token *in) {
if (in) {
for (int i = 0; in[i] != TERMINAL; i++)
free(in[i].value);
free(in);
}
}
Here are additional remarks for the rest of the code:
why clear the screen on entry and exit?
you should test for end of file in the main loop:
if (!fgets(user_in, 1024, stdin))
break;
you should strip the newline efficiently:
#include <string.h>
user_in[strcspn(user_in, "\n")] = '\0';
then you can simplify the test for exit:
if (!strcmp(user_in, "exit"))
break;
no need to clear user_in after solve()
you could simplify testing by solving the command line arguments:
for (int i = 1; i < argc; i++)
solve(argv[i]);
you should ignore white space and accept empty lines
you should use "%.17g instead of %lf. Note that the l is mandatory
for scanf() for a double type, but ignored for printf, because
float arguments are converted to double when passed to vararg
functions like printf.
you should use a context structure and pass a pointer to it
to parse and its helper functions to avoid global variables
as you can see in try_add_sub and try_mul_div, it would simplify
the switch to unify token types and avoid the OPERATOR classification.
the parser is too complicated: you should use recursive descent more
directly: try_add_sub should first call try_mul_div and iterate on
additive operators, calling try_mul_div for each subsequent operand.
Similarly, try_mul_div should first call try_exp and try_exp would
call try_primitive which would handle parentheses and constants.
this approach consumes one token at a time, which can be read from
the expression source on the fly, bypassing the need for tokenizing the whole string.
you should accept the full number syntax for constants, which is easy with strtod().
Here is a simplified version along these directions:
//---- tokenize.h ----
#define TERMINAL 0
#define OPERAND 1
#define ERROR 2
#define ADD '+'
#define SUBTRACT '-'
#define MULTIPLY '*'
#define DIVIDE '/'
#define EXPONENT '^'
#define L_PARENTHESIS '('
#define R_PARENTHESIS ')'
#define SYNTAX_ERROR 1
#define PAREN_ERROR 2
typedef struct context {
char *p;
char *nextp;
int parenthesis_balance;
int error_code;
double value;
} context;
int this_token(context *cp);
void skip_token(context *cp);
//---- tokenize.c ----
#include <stdlib.h>
//#include "tokenize.h"
int this_token(context *cp) {
char *p = cp->p;
for (;;) {
switch (*p) {
case '\0':
cp->nextp = p;
return TERMINAL;
case ' ':
case '\t':
case '\n':
/* ignore white space */
p++;
continue;
case ADD:
case SUBTRACT:
case MULTIPLY:
case DIVIDE:
case EXPONENT:
case L_PARENTHESIS:
case R_PARENTHESIS:
/* single character operators */
cp->nextp = p + 1;
return *p;
default:
/* try and parse as a number constant */
cp->value = strtod(p, &cp->nextp);
if (cp->nextp > p)
return OPERAND;
return ERROR;
}
}
}
void skip_token(context *cp) {
cp->p = cp->nextp;
}
//---- parse.h ----
int parse(char expression[], double *result);
void solve(char expression[]);
//---- parse.c ----
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
//#include "tokenize.h"
//#include "parse.h"
/* expression parsers return non zero upon error */
int try_add_sub(context *cp, double *result);
int try_mul_div(context *cp, double *result);
int try_exp(context *cp, double *result);
int try_primary(context *cp, double *result);
int try_add_sub(context *cp, double *result) {
if (try_mul_div(cp, result))
return 1;
for (;;) {
double operand;
switch (this_token(cp)) {
case ADD:
skip_token(cp);
if (try_mul_div(cp, &operand))
return 1;
*result += operand;
continue;
case SUBTRACT:
skip_token(cp);
if (try_mul_div(cp, &operand))
return 1;
*result -= operand;
continue;
}
return 0;
}
}
int try_mul_div(context *cp, double *result) {
if (try_exp(cp, result))
return 1;
for (;;) {
double operand;
switch (this_token(cp)) {
case MULTIPLY:
skip_token(cp);
if (try_exp(cp, &operand))
return 1;
*result *= operand;
continue;
case DIVIDE:
skip_token(cp);
if (try_exp(cp, &operand))
return 1;
*result /= operand;
continue;
}
return 0;
}
}
int try_exp(context *cp, double *result) {
if (try_primary(cp, result))
return 1;
if (this_token(cp) == EXPONENT) {
double operand;
skip_token(cp);
if (try_exp(cp, &operand))
return 1;
*result = pow(*result, operand);
}
return 0;
}
int try_primary(context *cp, double *result) {
switch (this_token(cp)) {
case OPERAND:
skip_token(cp);
*result = cp->value;
return 0;
case L_PARENTHESIS:
skip_token(cp);
cp->parenthesis_balance++;
if (try_add_sub(cp, result))
return 1;
cp->parenthesis_balance--;
if (this_token(cp) != R_PARENTHESIS) {
cp->error_code = PAREN_ERROR;
return 1;
}
skip_token(cp);
return 0;
}
cp->error_code = SYNTAX_ERROR;
return 1;
}
/* parse and evaluate an expression, return error code, update result */
int parse(char expression[], double *result) {
context cc;
cc.nextp = cc.p = expression;
cc.parenthesis_balance = 0;
cc.error_code = 0;
cc.value = 0;
if (try_add_sub(&cc, result))
return cc.error_code;
if (this_token(&cc) != TERMINAL)
return SYNTAX_ERROR;
return 0;
}
void solve(char expression[]) {
double result = 0;
switch (parse(expression, &result)) {
case 0:
printf(" %.17g\n", result);
break;
case SYNTAX_ERROR:
printf("ERROR: Syntax\n");
break;
case PAREN_ERROR:
printf("ERROR: Unbalanced parenthesis\n");
break;
}
}
//---- calculator.c ----
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include "parse.h"
int main(int argc, char **argv) {
for (int i = 1; i < argc; i++)
solve(argv[i]);
if (argc == 1) {
char user_in[1024];
char *p;
printf("Terminal Calculator\n");
printf("Type 'exit' to terminate\n\n");
for (;;) {
printf("=> ");
if (!fgets(user_in, sizeof user_in, stdin)) {
printf("\n");
break;
}
/* strip trailing newline */
user_in[strcspn(user_in, "\n")] = '\0';
/* skip initial white space */
p = user_in + strspn(user_in, " \t");
/* ignore empty and comment lines */
if (*p == '\0' || *p == '#')
continue;
/* trap exit command */
if (!strcmp(p, "exit"))
break;
solve(p);
}
}
return 0;
}
For class, I have to write a code that checks for balanced parentheses. The input will be given through stdin (running it as: code.exe < in.txt)
The input is formatted like this:
CASE 1: (())
CASE 2: [})(
CASE n: ...
***end***
I coded it like this:
int main(void) {
char test[200];
char str[200];
char end[] = "***end***";
int caseNo = 1;
int j;
int flag;
while(1) {
if(strcmp(fgets(test, 200, stdin), end) == 0) {
break;
} else {
strcpy(str, test);
int len = strlen(str);
for(int i = 0; i < len; i++) {
if(str[i] == ':') {
j = i + 2;
break;
}
}
flag = balanced_parenthesis(str, j);
if(flag == 0) {
printf("CASE %d: NOT BALANCED\n", caseNo);
} else if(flag == 1) {
printf("CASE %d: BALANCED\n", caseNo);
}
caseNo++;
}
}
But, the output that comes out is wrong. I've already checked my balanced_parenthesis function separately, and it does work, which leads me to believe that the error is in reading the input.
Am I using fgets or strcmp wrong? Is there a better way to read the input?
Edit:
Full Code is shown here:
#include <stdio.h>
#include <string.h>
int top = -1;
char stack[200];
void push(char c) {
top++;
stack[top] = c;
}
char pop() {
return(stack[top--]);
}
int pairs(char open, char close) {
if(open == '(' && close == ')') {
return 1;
} else if (open == '[' && close == ']') {
return 1;
} else if (open == '{' && close == '}') {
return 1;
}
return 0;
}
int balanced_parenthesis(char str[], int j) {
int len = strlen(str);
for(int i = j; i < len; i++) {
if((str[i] == '(') || (str[i] == '[') || (str[i] == '{')) {
push(str[i]);
}
if((str[i] == ')') || (str[i] == ']') || (str[i] == '}')) {
if(top == -1) { //empty
return 0;
} else {
char temp = pop();
if(pairs(temp, str[i]) == 0) {
return 0; //not pairs
}
}
}
}
if(top == -1) {
return 1; //balanced
} else {
return 0; //not balanced
}
}
int main(void) {
char test[200];
char str[200];
char end[] = "***end***";
int caseNo = 1;
int j;
int flag;
while(1) {
if(fgets(test, 200, stdin) == NULL) {
break;
} else {
test[strcspn(test, "\n")] = '\0';
if(strcmp(test, end) == 0) {
break;
} else {
strcpy(str, test);
int len = strlen(str);
for(int i = 0; i < len; i++) {
if(str[i] == ':') {
j = i + 2;
break;
}
}
flag = balanced_parenthesis(str, j);
if(flag == 0) {
printf("CASE %d: NOT BALANCED\n", caseNo);
} else if(flag == 1) {
printf("CASE %d: BALANCED\n", caseNo);
}
caseNo++;
}
}
}
}
Sample Input:
CASE 1: ([[]{()}])()
CASE 2: ()[]{}
CASE 3: (([[]))
CASE 4: (()}
CASE 5: (()()()())
CASE 6: (((())))
CASE 7: (()((())()))
CASE 8: ((((((())
CASE 9: ()))
CASE 10: (()()(()
CASE 11: ][
CASE 12: ({)}
***end***
Expected Output:
CASE 1: BALANCED
CASE 2: BALANCED
CASE 3: NOT BALANCED
CASE 4: NOT BALANCED
CASE 5: BALANCED
CASE 6: BALANCED
CASE 7: BALANCED
CASE 8: NOT BALANCED
CASE 9: NOT BALANCED
CASE 10: NOT BALANCED
CASE 11: NOT BALANCED
CASE 12: NOT BALANCED
There is a logical flaw in your code:-
for every line that you wish to check - before that you must ensure to rest the state of the stack. That's what you didn't do which caused problem.
void stack_reset(){
top = -1;
}
In main()
...
if(strcmp(test, end) == 0) {
break;
} else {
reset();
strcpy(str, test);
...
This change will make your code work. Otherwise it was handling with previous state also.
As you have \n as input to the char array test your comparison fails.
Considering that your rest of the code is alright , there is a single change you need to do to make this work. (This is problem if there is \n at the end of the input file). It is still good to add this solution - that will make this solution work irrespective of newline at the last line of the file.
while(1) {
if( !fgets(test, 200, stdin) ){
/* error handling*/
}
test[strcspn(test,"\n")]='\0';
if(strcmp(test, end) == 0) {
break;
} else {
...
You are overwriting the \n with the \0 because strcspn returns the number of character read before it encounters any of the character specified in the second parameter to strcspn.
Also once return statement is executed there is no use of the break statement as control never reach that point. And you exit from the function.
if(pairs(temp, str[i]) == 0) {
return 0; //not pairs
// break; <-- not needed.
}
The way you took input won't fail when you have the input file ended with no newline. If there is then the last comparison with ***end*** will fail.
The reason behind making the reset() function separate from your main() module is that - if later you need to change the implementation of stack then the user code won't be affected. It can still call the reset() and be sure that it will reset the state of the stack. Also as another suggestion, try not to make the stack variable top global, even better if you can pass the structure from function to function instead of using global one.
I have a problem. I've wrote a program that changes input according to chosen argument. Program works how I want it to work, but it wasnt accepted because it need to work on whole lines (with fgets I belive) instead of characters one by one. Second thing is it should print values in main function.
I can't deal with none with that problems, could I get some help.
main.c
#include <stdlib.h>
#include <stdio.h>
#include "WordTools.h"
int main(int argc, char *argv[]) {
char string[1000];
size_t i = 0;
while (i < sizeof string) {
int ch = getchar();
if (ch == EOF) break;
string[i] = ch;
i++;
}
string[i] = 0;
switch (argc > 1 && argv[1][1]) {
case 'l':
case 'L':
makeLower(string);
break;
case 'u':
case 'U':
break;
case 'c':
case 'C':
makeChange(string);
break;
case 'n':
case 'N':
makeName(string);
break;
default:
makeUpper(string);
break;
}
return 0;
}
WordTools.c
#include <stdio.h>
#include <ctype.h>
#include "WordTools.h"
void makeLower(char *s) {
int i;
for(i = 0; s[i] != '\0'; i++){
s[i] = tolower(s[i]);
}
printf("%s", s);
}
void makeUpper(char *s) {
int i;
for(i = 0; s[i] != '\0'; i++){
s[i] = toupper(s[i]);
}
printf("%s", s);
}
void makeChange(char *s) {
int i;
for(i = 0; s[i] != '\0'; i++){
if ((s[i] >= 65) && (s[i] <= 90)) s[i] = tolower(s[i]);
else if ((s[i] >= 97) && (s[i] <= 122)) s[i] = toupper(s[i]);
}
printf("%s", s);
}
void makeName(char *s) {
int i;
s[0]=toupper(s[0]);
for(i = 1; s[i] != '\0'; i++){
s[i] = tolower(s[i]);
}
printf("%s", s);
}
PROBLEM:
Write a C program that prompts the user to enter a string of characters terminated by ENTER key (i.e. ‘\n’) and then count the total number of the occurrence of each vowel in the string. Your program should use the following guidelines:
• Your program should declare an array of 5 integer counters, namely counter.
• Using a loop, your program should initialize each member of the array to 0.
• Each character in the string is then checked to see if it is a vowel, i.e. ‘a’, ‘e’, ‘i’, ‘o’ or ‘u’. In that case, the corresponding counter is incremented. For example if an ‘a’ is read then counter[0] is incremented, if an ‘i’ is read then counter[2] is incremented and so on.
• The entered characters could be lower or upper case.
• Your program should use a loop to printout the contents of the 5 counters.
• Lastly your program should print the total number of vowels in the string.
The result should look like:
Please enter a string terminated by ENTER key:
“The brown fox jumped over the lazy dog”
counter[0] = 1
counter[1] = 4
counter[2] = 0
counter[3] = 4
counter[4] = 1
Total number of Vowels= 10
MY CODE:
#include <stdio.h>
main(){
int counter[5];
int c, i;
for(i = 0; i < 5; i++)
counter[i] = 0;
printf("Please enter a string terminated by ENTER key:\n");
while((c = getchar()) != '\n')
{
if((counter[i] == 'a' || counter[i] == 'e' || counter[i] == 'i' || counter[i] ==
'o' || counter[i] == 'u') ||(counter[i] == 'A' || counter[i] == 'E' || counter[i] ==
'I' || counter[i] == 'O' || counter[i] == 'U'))
{
for(i = 0; i < 5; i++)
{
if(c == 'a' + i)
counter[i] = counter[i] + 1;
}
}
}
for(i = 0; i < 5; i++)
printf("counter[%d] = %d\n", i, counter[i]);
}
What's wrong with my counter?
Thanks in advance.
First of all you should put the return type for main: int ( ex: int main() ), this did not break your code but it the C standard and rises a warning from the compiler.
Chars in C take the numerical value from the ASCII encoding standard: http://upload.wikimedia.org/wikipedia/commons/1/1b/ASCII-Table-wide.svg, look at the values there ( 'a' is 97 for example), more on wikipedia : http://en.wikipedia.org/wiki/ASCII
All you do in your last for loop is compare the character to a,b,c,d,e.
What I would recommend you to do is make a switch for the character:
switch(c) {
case 'a':
case 'A':
counter[0]++;
break;
case 'e':
case 'E':
counter[1]++;
break;
case 'i':
case 'I':
counter[2]++;
break;
case 'o':
case 'O':
counter[3]++;
break;
case 'u':
case 'U':
counter[4]++;
break;
}
Alternatively, you could make five if statements.
It should work fine now.
(just for fun, my answer)
int main(void)
{
int counter[5] = {0};
int *i, c;
printf("Please enter a string terminated by ENTER key:\n");
while(i = counter, (c = getchar()) != '\n')
{
switch(c)
{
default: continue;
case 'U'+' ': case 'U': ++ i;
case 'O'+' ': case 'O': ++ i;
case 'I'+' ': case 'I': ++ i;
case 'E'+' ': case 'E': ++ i;
case 'A'+' ': case 'A': ++*i;
}
}
for(c = 0; c < 5;
printf("counter[%d] = %d\n", c, counter[c++]));
return 0;
}
I think this is what you are trying to do:
printf("Please enter a string terminated by ENTER key:\n");
while((c = getchar()) != '\n')
{
if (c=='a' || c=='A')
counter[0]++;
else if (c=='e' || c=='E')
counter[1]++;
else if (c=='i' || c=='I')
counter[2]++;
else if (c=='o' || c=='O')
counter[3]++;
else if (c=='u' || c=='U')
counter[4]++;
}
for(i = 0; i < 5; i++)
printf("counter[%d] = %d\n", i, counter[i]);
OR using switch:
printf("Please enter a string terminated by ENTER key:\n");
while((c = getchar()) != '\n')
{
switch(c)
{
case 'a':
case 'A': counter[0]++;
break;
case 'e':
case 'E': counter[1]++;
break;
case 'i':
case 'I': counter[2]++;
break;
case 'o':
case 'O': counter[3]++;
break;
case 'u':
case 'U': counter[4]++;
break;
default: break;
}
}
for(i = 0; i < 5; i++)
printf("counter[%d] = %d\n", i, counter[i]);
while((c = getchar()) != '\n')
{
if((counter[i] == 'a' || counter[i] == 'e' || counter[i] == 'i' || counter[i] ==
'o' || counter[i] == 'u') ||(counter[i] == 'A' || counter[i] == 'E' || counter[i] ==
'I' || counter[i] == 'O' || counter[i] == 'U'))
{
for(i = 0; i < 5; i++)
{
if(c == 'a' + i)
counter[i] = counter[i] + 1;
}
}
}
I feel the logic in this code may be wrong because, you have initialized your counter[0] with 0 and then you are comparing it with 'a' or 'A' but not the char c, so use
while((c = getchar()) != '\n')
{
if(c == 'a' || c == 'A')
{
i = 0;
counter[i] =+ 1;
}
else if( c == 'i' || c == 'I' )
{
i = 1;
counter[i] =+ 1;
}
...//and so on
}
Apparantly none of the other answerers so far have noticed these possibilities to improve the code:
Define the vowels as a string and write a function that returns the index of the vowel in that string (or -1 in case of a not-a-vowel error).
Convert the character to lowercase before doing the comparison. This is a very common approach to achieve case insensitive behavior.
You should also check for EOF as an exit condition for your loop.
I think, what you need is something like this:
#include <stdio.h>
#include <ctype.h>
const char vowels[] = "aeiou";
int findvowel(char c) {
int i;
c = tolower(c);
for (i=0; vowels[i]; i++)
if (vowels[i] == c)
return i;
return -1;
}
int main() {
char c;
int i, sum;
int counter[sizeof(vowels)] = {0};
while (c=getchar(), c != EOF && c != '\n') {
i = findvowel(c);
if (i != -1)
counter[i] += 1;
}
printf("having found these vowels:\n");
for (i=0, sum=0; vowels[i]; i++) {
printf("'%c': %d\n", vowels[i], counter[i]);
sum += counter[i];
}
printf("total: %d %s\n", sum, sum != 1 ? "vowels" : "vowel");
return 0;
}