Calculator in C using stack - c

I'm trying to create a calculator in c, which can calculate with priority and get right results for examples like these:
((5+5)/3)*3) -- > 9
((1+2) * 3) -- > 9
These examples my code below can calculate. But for something like this
(2+5) * (2+5), my program gives wrong answer.
I'm using 2 stacks. One for operators and one for numbers. It works on this principle:
follows:
((4 - 2) * 5) + 3 --> normal infix expression:
+ * - 4 2 5 3
Pseudo code:
Read + (an operation), push it onto the stack,
Read * (an operation), push it onto the stack,
Read - (an operation), push it onto the stack,
Read 4 (a number), the top of the stack is not a number, so push it onto the stack.
Read 2 (a number), the top of the stack is a number, so pop from the stack twice, you get 4 - 2, calculate it (2), and push the result (2) onto the stack.
Read 5 (a number), the top of the stack is a number, so pop from the stack twice, you get 2 * 5, push the result (10) onto the stack.
Read 3 (a number), the top of the stack is a number, so pop from the stack twice, you get 3 + 10, push the result (13) onto the stack.
Nothing left to read, pop from the stack and return the result (13).
Actual code:
#include <stdio.h>
#include<ctype.h>
#include<stdlib.h>
#include<string.h>
#define MAXSIZE 102
typedef struct
{
char stk[MAXSIZE];
int top;
}STACK;
typedef struct stack
{
int stk[MAXSIZE];
int itop;
}INT_STACK;
STACK s;
INT_STACK a;
void push(char);
char pop(void);
void display(void);
int main()
{
a.itop = 0;
char string[MAXSIZE],vyb,vyb2;
int cislo1,cislo2,vysledok;
while (gets(string) != NULL){
for(int j = strlen(string); j > 0; j--){
if(string[j] == '*' || string[j] == '/' || string[j] == '+' || string[j] == '-')
push(string[j]);
}
//display();
for(int j = 0; j < strlen(string); j++){
if(isdigit(string[j])&&!(a.itop)){
//display();
char pomoc[2];
pomoc[0] = string[j];
pomoc[1] = '\0';
int_push(atoi(pomoc));
}
else if(isdigit(string[j])&&(a.itop)){
cislo1 = int_pop();
vyb2 = pop();
char pomoc[2];
pomoc[0] = string[j];
pomoc[1] = '\0';
cislo2 = atoi(pomoc);
if(vyb2 == '+')
vysledok = cislo1+cislo2;
else if(vyb2 == '-')
vysledok = cislo1-cislo2;
else if(vyb2 == '*')
vysledok = cislo1*cislo2;
else if(vyb2 == '/')
vysledok = cislo1 / cislo2;
//printf(" v %d",vysledok);
int_push(vysledok);
}
}
printf("%d\n",int_pop());
}
}
/* Function to add an element to the stack */
void push (char c)
{
s.top++;
s.stk[s.top] = c;
//printf ("pushed element is = %c \n", s.stk[s.top]);
}
/* Function to delete an element from the stack */
char pop ()
{
char num = s.stk[s.top];
// printf ("poped element is = %c\n", s.stk[s.top]);
s.top--;
return(num);
}
int empty()
{
if (s.top == - 1)
{
printf ("Stack is Empty\n");
return (s.top);
}
return 1;
}
void display ()
{
int i;
if (!empty)
{
printf ("Stack is empty\n");
return;
}
else
{
printf ("\n The status of the stack is \n");
for (i = s.top; i >= 0; i--)
{
printf ("%c\n", s.stk[i]);
}
}
printf ("\n");
}
void int_push (int c)
{
a.itop++;
a.stk[a.itop] = c;
//printf ("pushed element is = %d \n", a.stk[a.itop]);
}
/* Function to delete an element from the stack */
int int_pop ()
{
int num = a.stk[a.itop];
// printf ("poped element is = %d\n", a.stk[a.itop]);
a.itop--;
return(num);
}
Is there any other way to create a calculator with priority, which can give good answers?
Thanks for your respond

Put breakpoints - you'll get the following expression:
+ + * 2 5 2 5. The problem with that, is your interpreter is interpeting this as (2+5+2)*5 instead of (2+5) * (2+5).
Well then, you might be wondering how to solve this. There's no simple single solution - you could either fix your own interpreter or build a whole new mechanic, because the way you build expressions just can't handle more then one pair of parthesises.
For example, you may want to calculate all the values in parnthesises before even building the expression seperatley, possibly using recursion in the case of parenthesiseception - however if you actually choose to use that method, you might want to change the way you work with the expressions entirely, because that's a different approach.
If you need me to show actual code examples to explain this further using parts of the code you made, just ask for it and i'll edit and provide what you need.
Either way, I really advise you to look up working with interpreters in general - you could really learn a lot about analysing strings and working with different inputs, and people even did similar stuff to yours with calculators before
EDIT: you asked for examples, so here you go - this is an example of a completely different method using recursion. This way, you handle a single pair of parenthesises at a time, and thus you won't have the problem you currently do. Note - the source i'm basing this on ( pretty much copy-pasted with edits from the thread and some personal comments ) is from codereview on stack exchange, you can see it here
if you're intrested.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void getInput(char * in) {
printf("> ");
fgets(in, 256, stdin);
}
int isLeftParantheses(char p) {
if (p == '(') return 1;
else return 0;
}
int isRightParantheses(char p) {
if (p == ')') return 1;
else return 0;
}
int isOperator(char p) {
if (p == '+' || p == '-' || p == '*' || p == '/') return p;
else return 0;
}
int performOperator(int a, int b, char p) {
switch(p) {
case '+': return a+b;
case '-': return a-b;
case '*': return a*b;
case '/':
if (b == 0) { printf("Can't divide by 0, aborting...\n"); exit(1); } // now we dont want the world to expload here do we.
return a/b;
default:
puts("Bad value in switch.\n"); // A replacement which was mentioned in the thread- better have a default response just in case something goes wrong.
break;
}
return 0;
}
char isDigit(char p) {
if (p >= '0' && p <= '9') return 1;
else return 0;
}
int charToDigit(char p) {
if (p >= '0' && p <= '9') return p - '0';
else return 0;
}
int isNumber(char * p) {
while(*p) {
if (!isDigit(*p)) return 0;
p++;
}
return 1;
}
int len(char * p)
{
return (int) strlen(p); // This was bugged in the source, so I fixed it like the thread advised.
}
int numOfOperands(char * p) {
int total = 0;
while(*p) {
if (isOperator(*p)) total++;
p++;
}
return total+1;
}
int isMDGRoup(char *p)
{
for(; *p; p++) // used to be a while loop in the source, but this is better imho. more readable, also mentioned on the thread itself.
{
if (!isDigit(*p) && *p != '/' && *p != '*') return 0;
}
return 1;
}
int getLeftOperand(char * p, char * l) {
// Grab the left operand in p, put it in l,
//and return the index where it ends.
int i = 0;
// Operand is part of multi-*/ group
if (isMDGRoup(p)) {
while(1) {
if (*p == '*' || *p == '/') break;
l[i++] = *p++;
}
return i;
}
// Operand is in parantheses (so that's how you write it! sorry for my bad english :)
if(isLeftParantheses(*p)) {
int LeftParantheses = 1;
int RightParantheses= 0;
p++;
while(1) {
if (isLeftParantheses(*p)) LeftParantheses++;
if (isRightParantheses(*p)) RightParantheses++;
if (isRightParantheses(*p) && LeftParantheses == RightParantheses)
break;
l[i++] = *p++;
}
// while (!isRightParantheses(*p)) {
// l[i++] = *p++;
// }
l[i] = '\0';
return i+2;
}
// Operand is a number
while (1) {
if (!isDigit(*p)) break;
l[i++] = *p++;
}
l[i] = '\0';
return i;
}
int getOperator(char * p, int index, char * op) {
*op = p[index];
return index + 1;
}
int getRightOperand(char * p, char * l) {
// Grab the left operand in p, put it in l,
//and return the index where it ends.
while(*p && (isDigit(*p) || isOperator(*p) ||
isLeftParantheses(*p) || isRightParantheses(*p))) {
*l++ = *p++;
}
*l = '\0';
return 0;
}
int isEmpty(char * p) {
// Check if string/char is empty
if (len(p) == 0) return 1;
else return 0;
}
int calcExpression(char * p) {
// if p = #: return atoi(p)
//
// else:
// L = P.LeftSide
// O = P.Op
// R = P.RightSide
// return PerformOp(calcExpression(L), calcExpression(R), O)
// ACTUAL FUNCTION
// if p is a number, return it
if (isNumber(p)) return atoi(p);
// Get Left, Right and Op from p.
char leftOperand[256] = ""; char rightOperand[256]= "";
char op;
int leftOpIndex = getLeftOperand(p, leftOperand);
int operatorIndex = getOperator(p, leftOpIndex, &op);
int rightOpIndex = getRightOperand(p+operatorIndex, rightOperand);
printf("%s, %c, %s", leftOperand, op, rightOperand);
getchar();
if (isEmpty(rightOperand)) return calcExpression(leftOperand);
return performOperator(
calcExpression(leftOperand),
calcExpression(rightOperand),
op
);
}
int main()
{
char in[256];
while(1) {
// Read input from user
getInput(in);
if (strncmp(in, "quit", 4) == 0) break;
// Perform calculations
int result = calcExpression(in);
printf("%d\n", result);
}
}

Related

Trying to copy a char pointer to a pointer to use with a flood fill function in 2D game

As part of a 2D game I am building I need to check if there is a valid path for the game to be completed. It was recommended that I do a copy of the map and use flood fill to check the validity. The characters in the game are a 'P (player), 'E' (exit), 'C' (collectable), '1' (wall) and '0' (spaces). I have a typedef structure called t_map that holds all of my game variables.
Currently it is seg faulting on the flood fill but this is because the copy_map is not working. I have only started c programming six months ago so to get to this stage has been a challenge. So my understanding of what should happen is:
copy each line of the map.ber file using the copy_map function.
if it finds a 'C' change to a '0' and increment copy_ccount.
else if it finds an 'E' change to a '0' and increment copy_ecount
if it is an '0' use flood fill to check each space around it and move through the map "painting" the '0' with a 'P'.
do a check against ccount and ecount from the original map and if they are different throw an error.
My question is instead of trying to copy it line by line should I in fact be opening the map and reading it again? I've had help with the read_map function and the copy_map function from two different people so trying to tie it all together is proving difficult. Thanks for any assistance.
#include <stdio.h>
#include <unistd.h>
void copy_map(char **origin, char **copy)
{
int i;
i = 0;
while (copy[i])
{
origin[i] = ft_strdup(copy[i]); //this is my own strdup function
i++;
}
origin[i] = NULL;
}
static void flood_fill(t_map *map, int paint, int y, int x)
{
if (map->map_copy[y][x] == 'C')
{
map->copy_ccount++;
map->map_copy[y][x] = '0';
}
else if (map->map_copy[y][x] == 'E')
{
map->copy_ecount++;
map->map_copy[y][x] = '0';
}
if (map->map_copy[y][x] == '0')
{
map->map_copy[y][x] = paint;
flood_fill(map, paint, y, x + 1);
flood_fill(map, paint, y, x - 1);
flood_fill(map, paint, y + 1, x);
flood_fill(map, paint, y - 1, x);
}
}
int valid_path(t_map *map, int y, int x)
{
map->map_copy = ft_calloc(1, sizeof(map->map)); // this is my own calloc function
y = map->playery;
x = map->playerx;
copy_map(map->map, map->map_copy);
flood_fill(map, 'P', y, x);
if (map->ccount != map->copy_ccount)
{
closeprogram("Map cannot be solved\n");
}
if (map->ecount != map->copy_ecount)
{
closeprogram("Map cannot be solved\n");
}
return (1);
}
This is the original read_map function and the main that pulls it all together.
t_map *read_map(char *argv )
{
t_map *new;
int y;
new = (t_map *) ft_calloc(1, sizeof(t_map));
new->fd = open(argv, O_RDONLY);
new->h = 0;
new->w = 0;
y = 0;
if (new->fd < 0)
{
ft_putstr("Map file does not exist\n");
exit (1);
}
while (get_next_line(new->fd))
new->h += 1;
close (new->fd);
new->map = (char **) ft_calloc(new->h + 1, sizeof(char *));
new->fd = open(argv, O_RDONLY);
while (y < new->h)
{
new->map[y] = get_next_line(new->fd);
y++;
}
while (new->map[0][new->w++ + 2])
close(new->fd);
return (new);
}
int main(int argc, char **argv)
{
t_map *map;
if (argc != 2)
{
ft_putstr("Error\nInvalid number of arguments. Must be 2\n");
return (1);
}
if (check_map_file(argv[1]))
return (1);
map = read_map(argv[1]);
init_components(map);
valid_map(map);
map->mlx = mlx_init();
map->win = mlx_new_window(map->mlx, map->w * 32, map->h * 32, "so_long");
render_map(map);
parse_map(map);
mlx_hook(map->win, 17, 0, exitprogram, NULL);
mlx_hook(map->win, 2, 1L << 0, keypress_hook, map);
mlx_loop(map->mlx);
return (0);
}

How to generate a new function in C?

I want a function that could take input a single integer from the user with validation, lets call it input_single_int. Such a function would greatly simplify my code. If a user gives incorrect input, then the function should show error and again prompt the user to fill out the correct input. The problem is the validation part, different inputs require different validation. Even if I send a validation function, how do I send the different parameters required by the validation function through input_single_int?
I want this function to be generic, so that I could use it multiple places. In the code given, if I add a parameter in input_single_int to accomodate input of variable b, I would have to change check_a function also, which I don't want to do. I also don't want to use global variables.
The only way which I could think of achieving this is through a function that could generate another function. Something like this:
func generate_check_b(int a) {
return int check_b(int b) { return (b > 0 && b < a); };
}
Is such a thing possible in C?
#define MM_SHOW 8
#define MM_QUIT 9
int input_single_int(int *var, char msg[], int exit_on_eq, int secondary_check(int val)) {
int inp_status, error, temp;
char skip;
do {
error = 0;
printf("%s", msg);
inp_status = scanf("%d", &temp);
if (inp_status != 1) {
error = 1;
do {
scanf("%c", &skip);
if (exit_on_eq) {
if (skip == 'e') {
system("clear");
return MM_SHOW;
} else if (skip == 'q') {
system("clear");
return MM_QUIT;
}
}
} while (skip != '\n');
}
if (!secondary_check(temp)) {
error = 1;
}
} while (error && printf("Please give a correct input.\n"));
*var = temp;
return 0;
}
int check_a(int a) { return a > 0;}
int check_b(int b, int a) { return (b > 0 && b < a);}
int main() {
int a, b;
char amsg[] = "a should be more than 0: ";
char bmsg[] = "b should be more than 0 and less than a: ";
input_single_int(&a, amsg, 1, check_a);
input_single_int(&b, bmsg, 1, check_b);
return 0;
}
A common idiom is a pair of parameters; a function and an opaque context pointer; so a simple case could be something like:
int check_range(int a, void *p) {
int *range = p;
return a >= range[0] && a < range[1];
}
struct Set { int n; int *vals; };
int check_set(int b, void *p) {
struct Set *s = p;
int i;
for (i = 0; i < s->n && s->vals[i] != b; i++) {}
return i < s->n;
}
If you look at the blocks extension to C supported by clang & gcc, it isn't far different from this, except that it is more sugary and has some really scary side effects.

Find all vowels which never used in all words in the text

I wrote code that find all vowels which used in all words in the text. And I do not know how to transfer it. Do I need to rewrite all code?
So, I need to have such results:
Text:
wwe w fa
Result:
o u i
#include <stdio.h>
#include <ctype.h>
#define vowel (1u<<('a'-'a') | 1u<<('e'-'a') | 1u<<('i'-'a') | 1u<<('o'-'a') | 1u<<('u'-'a'))
unsigned int char_to_set(char c)
{
c = tolower(c);
if (c < 'a' || c > 'z')
return 0; else return 1u<<(c-'a');
}
int letter(int c)
{
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
int sign(int c)
{
return c == ' ' || c == ',' || c == '\n' || c == '\t';
}
int main ()
{
int c, flag=0;
char alpha;
unsigned int sl = 0, mn = vowel;
FILE *pf;
pf=fopen("l13.txt","r");
printf ("Ishodnyi text:\n\n");
while (!feof(pf))
{
c=getc(pf);
printf("%c",c);
switch (flag)
{
case (0):
{
if (letter(c))
{
sl = sl | char_to_set(c);
flag = 1;
}
if (sign(c)) flag = 0;
break;
}
case (1):
{
if (letter(c))
{
sl = sl | char_to_set(c);
flag = 1;
}
if (sign(c))
{
mn = mn & sl;
sl = 0;
flag = 0;
}
break;
}
}
}
if (mn == 0) { printf ("\n\n no vowels are included in all word"); } else { printf ("\n\n vowels are included in all word:\n"); for(alpha='a'; alpha <= 'z'; alpha++){ if((mn & char_to_set(alpha)) != 0){ printf("%c ", alpha);
}
}
}
fclose(pf);
getchar();
return 0;
}
There are many ways to do what you want. Below is one way. There may be better ways but hopefully it will give you some ideas to improve it.
If I understand your code correctly, mn contains the bit mask of vowels present in the text. So you can write a function to check all the vowel bits that are not set. The following code checks for a and e only but I think it should be clear how to extend it for the other other vowels.
#define A_MASK (1u<<('a'-'a'))
#define E_MASK (1u<<('e'-'a'))
/*
* Convenience struct for associating masks with characters.
* Could be done without this by deriving the character from the mask
* but this (IMHO) makes the code simpler to understand.
*/
struct {
unsigned int mask
char c;
} masks[] = { { A_MASK, 'a'} , { E_MASK, 'e'} };
void vowels_not_present (unsigned int vowels_mask)
{
int ix;
for (ix = 0; ix < sizeof(masks) / sizeof(masks[0]); ix++) {
if (!(vowels_mask & masks[ix].mask)) {
printf("vowel %c is not present\n", masks[ix].c);
}
}
}
Then in your main invoke the above function:
vowels_not_present(mn);

Input line freezing, segmentation fault

I'm working on a project for a class and have been stuck for quite a while. When I unit tested the input earlier, it accepted the values for numOfDataSets and createDataSets without error. Now, however, after typing in any set of values for createDataSets, the code freezes after the first input until I enter any character (such as 1 or a), then errors with a segmentation fault. I am not sure what went wrong, and I would appreciate any help.
#include <stdio.h>
#include <stdlib.h>
// Function to return the number of data sets the user wants.
int numOfDataSets(void) {
int ret;
printf("Enter number of data sets: ");
scanf("%d", &ret);
return ret;
}
// Function that creates the data sets in the input arrays.
void createDataSets(float **inputArr, int inputLength, int *lengths) {
int i = 0, j, k;
float value, *currentSet;
// For every element in inputArr...
while (i < inputLength) {
printf("Enter the number of values in this data set, followed by the values: ");
scanf("%d", &j);
*(lengths + i) = j;
currentSet = (float*)calloc(j, sizeof(float));
k = 0;
while (k < j-1) {
scanf("%f", &value);
*(currentSet + k) = value;
k++;
}
scanf("%f", &value);
*(currentSet + j - 1) = value;
*(inputArr + i) = (float*)&currentSet;
i++;
}
}
// Function to get int value of data set to choose.
int chooseDataSet(void) {
int ret;
printf("Enter the number of the data set on which you wish to do calculations: ");
scanf("%d", &ret);
ret = ret - 1;
return ret;
}
// Gets the number option of the operation that the user wants to do.
int getOption(void) {
int ret;
printf("Enter one of the following numbers:\n");
printf("1. Find the minimum value.\n");
printf("2. Find the maximum value.\n");
printf("3. Calculate the sum of all the values.\n");
printf("4. Calculate the average of all the values.\n");
printf("5. Sort the values in ascending order (i.e., from smallest to largest).\n");
printf("6. Select a different data set.\n");
printf("7. Exit the program.\n");
scanf("%d", &ret);
return ret;
}
// Function to find the minimum value of a dataset.
void minimum(float *ptr, int length) {
int i = 1;
float min;
min = *(ptr);
while (i < length) {
if (*(ptr + i) < min) {
min = *(ptr + i);
}
i++;
}
printf("The minimum value of the set is: %d\n", min);
}
// Function to find the maximum value of a dataset.
void maximum(float *ptr, int length) {
int i = 1;
float max;
max = *(ptr);
while (i < length) {
if (*(ptr + i) > max) {
max = *(ptr + i);
}
i++;
}
printf("The maximum value of the set is: %d\n", max);
}
// Function to find the sum of the values of a dataset.
void sum(float *ptr, int length) {
int i = 1;
float sum;
sum = *(ptr);
while (i < length) {
sum = sum + *(ptr + i);
i++;
}
printf("The sum of the set is: %d\n", sum);
}
// Function to find the average of the values of a dataset.
void average(float *ptr, int length) {
int i = 1;
float sum;
sum = *(ptr);
while (i < length) {
sum = sum + *(ptr + i);
i++;
}
sum = sum / length;
printf("The average of the set is: %d\n", sum);
}
// Function to sort the values of a dataset.
void sort(float *ptr, int length) {
int i = 1, j;
float temp;
while (i < length) {
j = i;
while ((j > 0) && (*(ptr + j - 1) > *(ptr + j))) {
temp = *(ptr + j);
*(ptr + j) = *(ptr + j - 1);
*(ptr + j - 1) = temp;
j--;
}
i++;
}
printf("The sorted array is: ");
i = 0;
while (i < length) {
printf("%f\t", *(ptr + i));
i++;
}
printf("\n");
}
// Main method...
int main(void) {
int *lengths, outerLength, userChoiceSet = 0, userChoiceOption = 0, breakOutterLoop = 0;
float **outer;
outerLength = numOfDataSets();
outer = (float**)calloc(outerLength, sizeof(float*));
lengths = (int*)calloc(outerLength, sizeof(int));
createDataSets(outer, outerLength, lengths);
while (breakOutterLoop == 0) {
userChoiceSet = chooseDataSet();
while ((userChoiceOption != 6) || (userChoiceOption != 7)) {
userChoiceOption = getOption();
switch (userChoiceOption)
{
case 1:
minimum(*(outer + userChoiceSet), *(lengths + userChoiceSet));
break;
case 2:
maximum(*(outer + userChoiceSet), *(lengths + userChoiceSet));
break;
case 3:
sum(*(outer + userChoiceSet), *(lengths + userChoiceSet));
break;
case 4:
average(*(outer + userChoiceSet), *(lengths + userChoiceSet));
break;
case 5:
sort(*(outer + userChoiceSet), *(lengths + userChoiceSet));
break;
case 7:
breakOutterLoop = 1;
default:
break;
}
}
}
return (0);
}
The type of input to expect from the user would be something like:
2
3 1.2 2.3 3.4
4 4.5 5.6 6.7 7.8
Your main problem is this, in createDataSets():
*(inputArr + i) = (float*)&currentSet;
What this actually does is assign the address of currentSet to each element of inputArr. This address doesn't change on each iteration, so each element of inputArr gets set to the exact same value. Moreover, this address refers to a variable local to createDataSets() which will be destroyed when that function returns, so the address will be invalid. All the arrays you're dynamically creating are just being discarded, because you're not storing the addresses.
What you should have is:
inputArr[i] = currentSet;
As you mention in the comments, your compiler warned you about this, because what you were doing was trying to store a float ** in a float *, which is rarely a good idea. By adding the cast you silenced the warning, but you didn't fix the problem it was warning you about. The number of occasions in C where a cast is actually what you want to do are relatively few. None of the casts in your program are either necessary, or wise.
A few other points...
You use the wrong format specifier in many of your printf() calls. The %d here:
printf("The minimum value of the set is: %d\n", min);
for instance, should be an %f, because min is a float.
You are overusing pointer notation which makes your code very difficult to follow. That includes very difficult for you, too. For instance, your minimum() function could be much better written as so:
void minimum(float *ptr, int length) {
float min = ptr[0];
for ( int i = 0; i < length; ++i ) {
if ( ptr[i] < min ) {
min = ptr[i];
}
}
printf("The minimum value of the set is: %f\n", min);
}
Similarly, in your switch statement, something like:
average(*(outer + userChoiceSet), *(lengths + userChoiceSet));
is much more clearly written as:
average(outer[userChoiceSet], lengths[userChoiceSet]);
You are missing a call to fflush(stdout) in a few places, where you prompt for input but do not end the prompt with an '\n'. When I ran this code on my system, the prompt did not show before it sat to wait for the input. Interactive output is line-buffered by default, in C, and if you want things to be predictable, then you need to output a '\n' or call fflush(stdout) when output needs to be displayed.
You would benefit from defining your variables closer to the time of use. Restricting the scope of your variables to the minimum feasible is generally good. For instance, in your main() function, your variable userChoiceSet is never used outside of the outer while loop, so define it inside with:
while (breakOutterLoop == 0) {
int userChoiceSet = chooseDataSet();
You don't check the return from calloc() anywhere - you must do this, because the allocation might fail. malloc() and friends return NULL on failure. There's also no real point using calloc(), here - malloc() would be more normal.
You seem to use while loops in places where for loops would be much more natural.
You haven't done too bad a job with this one, but you'll find writing larger programs easier if you make each function do just one thing. For instance, your minimum() function should just calculate the minimum, but right now it calculates it and prints it. Particularly when it comes to dealing with input in the wrong format (see point 9 below) wrapping this up in a separate function will make the functions that use that input much less cluttered, and it's easy to get a function correct and to visually debug it if it's not doing a bunch of different things at once. Also, your opportunity for reusing code goes up when you do this (e.g. right now you couldn't use that minimum() function at any place where you wanted to calculate the minimum without also printing it).
Overall, having one array for your values, and a second for their lengths, is not a good approach. Far better would be to have an array of structs, each struct having a member for the array, and a member for the length, so the two related pieces of data are packaged together.
Also, your use of scanf() is potentially troublesome. If you enter input that's not expected, your program will not fail gracefully. For instance, if you enter anything other than a number in your main menu, then you'll go into an infinite loop. Generally better is to use fgets() to read in an entire line, and use sscanf() to parse its contents. At a minimum, you should check the return from scanf() to see if it successfully read a value, and if it did not, take appropriate remedial action (like reading all the characters in the input buffer and going back to ask for more input).
Overall, bearing all of the above in mind except for the last two points, your createDataSets() function would be better looking something like this:
void createDataSets(float **inputArr, const int inputLength, int *lengths) {
for ( int i = 0; i < inputLength; ++i ) {
printf("Enter the number of values in this data set, "
"followed by the values: ");
fflush(stdout);
scanf("%d", &lengths[i]);
float * currentSet = malloc(lengths[i] * sizeof *currentSet);
if ( !currentSet ) {
perror("Couldn't allocate memory in createDataSets()");
exit(EXIT_FAILURE);
}
for ( int j = 0; j < lengths[i]; ++j ) {
scanf("%f", &currentSet[j]);
}
inputArr[i] = currentSet;
}
}
Much easier to debug, easier to follow, and easier to not get wrong in the first place.
Since I've got a bit of time on my hands, here's how I'd figure it:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>
/* Maximum length of input buffer */
#define MAX_LINE 1024
/* Dataset structure */
struct dataset {
float * data;
size_t length;
};
/* Gets a single integer from user */
int getInteger(const char * prompt)
{
int value;
bool first_try = true;
char buffer[MAX_LINE];
do {
printf("%s%s: ", first_try ? "" : "Try again - ", prompt);
fflush(stdout);
fgets(buffer, MAX_LINE, stdin);
first_try = false;
} while ( sscanf(buffer, "%d", &value) != 1 );
return value;
}
/* Gets a bounded integer from user */
int getBoundedInteger(const char * prompt, const int min, const int max)
{
bool bad_input;
int value;
do {
bad_input = false;
value = getInteger(prompt);
if ( value < min ) {
printf("Too low, try again - ");
bad_input = true;
}
else if ( value > max ) {
printf("Too high, try again - ");
bad_input = true;
}
} while ( bad_input );
return value;
}
/* Gets a list of floats from user - caller must free */
float * getFloats(const char * prompt, const int num)
{
float * values = malloc(num * sizeof *values);
if ( !values ) {
perror("Couldn't allocate memory in getFloats()");
exit(EXIT_FAILURE);
}
bool bad_input = false;
do {
printf("%s%s: ", bad_input ? "Try again - " : "", prompt);
fflush(stdout);
char buffer[MAX_LINE];
fgets(buffer, MAX_LINE, stdin);
char * ptr = buffer;
int num_read = 0;
bad_input = false;
while ( *ptr && num_read < num ) {
/* Skip leading whitespace */
while ( *ptr && isspace(*ptr) ) {
++ptr;
}
/* Get and check input */
char * endptr;
float val = strtof(ptr, &endptr);
if ( ptr == endptr ) {
bad_input = true;
break;
}
/* Advance ptr and store input if good */
ptr = endptr;
values[num_read++] = val;
}
if ( num_read < num ) {
bad_input = true;
}
} while ( bad_input );
return values;
}
/* Returns the number of data sets the user wants. */
int numOfDataSets(void)
{
return getInteger("Enter number of data sets");
}
/* Creates the data sets */
void createDataSets(struct dataset ** sets, const int set_length)
{
for ( int i = 0; i < set_length; ++i ) {
struct dataset * new_set = malloc(sizeof *new_set);
if ( !new_set ) {
perror("Couldn't allocate memory for dataset");
exit(EXIT_FAILURE);
}
new_set->length = getInteger("Enter number of values in set");
new_set->data = getFloats("Enter values", new_set->length);
sets[i] = new_set;
}
}
/* Gets the number of data set to choose */
int chooseDataSet(const int min, const int max)
{
return getBoundedInteger("Choose data set", min, max) - 1;
}
/* Gets a menu choice from the user */
int getOption(void)
{
printf("Enter one of the following numbers:\n");
printf("1. Find the minimum value\n");
printf("2. Find the maximum value\n");
printf("3. Calculate the sum of all the values\n");
printf("4. Calculate the average of all the values\n");
printf("5. Sort the values in ascending order\n");
printf("6. Output the data set\n");
printf("7. Select a different data set\n");
printf("8. Exit the program\n");
return getInteger("Choose option");
}
/* Returns the minimum value in a data set */
float minimum(const struct dataset * set)
{
float min = set->data[0];
for ( size_t i = 0; i < set->length; ++i ) {
if ( set->data[i] < min ) {
min = set->data[i];
}
}
return min;
}
/* Returns the maximum value in a data set */
float maximum(const struct dataset * set)
{
float max = set->data[0];
for ( size_t i = 0; i < set->length; ++i ) {
if ( set->data[i] > max ) {
max = set->data[i];
}
}
return max;
}
/* Returns the sum of the data in a dataset */
float sum(const struct dataset * set)
{
float sum = 0;
for ( size_t i = 0; i < set->length; ++i) {
sum += set->data[i];
}
return sum;
}
/* Returns the arithmetic average of the data in a dataset */
float average(const struct dataset * set)
{
float sum = 0;
for ( size_t i = 0; i < set->length; ++i ) {
sum += set->data[i];
}
return set->length > 0 ? sum / set->length : sum;
}
/* Sorts the elements of a dataset in place */
void sort(struct dataset * set)
{
for ( size_t i = 0; i < set->length; ++i ) {
for ( size_t j = i; j && set->data[j-1] > set->data[j]; --j ) {
float temp = set->data[j];
set->data[j] = set->data[j-1];
set->data[j-1] = temp;
}
}
}
/* Prints a dataset */
void print_set(const struct dataset * set) {
for ( size_t i = 0; i < set->length; ++i ) {
printf("%.4f ", set->data[i]);
}
putchar('\n');
}
/* Main function */
int main(void)
{
/* Get and initialize sets */
const int num_sets = numOfDataSets();
struct dataset ** sets = malloc(num_sets * sizeof *sets);
if ( !sets ) {
perror("Couldn't allocate memory for sets");
return EXIT_FAILURE;
}
createDataSets(sets, num_sets);
/* Main menu */
int chosen_set = chooseDataSet(1, num_sets);
bool keep_going = true;
while ( keep_going ) {
switch ( getOption() )
{
case 1:
printf("Minimum value is %f\n\n",
minimum(sets[chosen_set]));
break;
case 2:
printf("Maximum value is %f\n\n",
maximum(sets[chosen_set]));
break;
case 3:
printf("Sum of values is %f\n\n",
sum(sets[chosen_set]));
break;
case 4:
printf("Average of values is %f\n\n",
average(sets[chosen_set]));
break;
case 5:
sort(sets[chosen_set]);
break;
case 6:
print_set(sets[chosen_set]);
break;
case 7:
chosen_set = chooseDataSet(1, num_sets);
break;
case 8:
keep_going = false;
break;
default:
break;
}
}
/* Free memory for sets */
for ( int i = 0; i < num_sets; ++i ) {
free(sets[i]->data);
free(sets[i]);
}
free(sets);
return 0;
}

Searching a particular word in a matrix of characters

I was trying to search for a particular word in a matrix of characters through C but was unable to come to a fixed solution.
For ex:
Suppose I have to search for the word INTELLIGENT in a matrix of characters (3*9)
(Once you have picked a character from the matrix to form a sentence, you cannot pick it again to form the same sentence.There is a path from any cell to all its neighboring cells. A neighbor may share an edge or a corner.)
IIIINN.LI
....TTEGL
.....NELI
Output: YES (the word INTELLIGENT can be found)
Can anybody please give a solution to the above problem !!!!
Use a depth first search.
You can do this using a recursive algorthm. Find all the (unused) places containing the first letter then see if it is possible to find the rest of the word on the remaining board by starting from one of the adjacent squares.
#include <stdio.h>
char Matrix[3][9] = {
{ 'I','I','I','I','N','N','.','L','I'},
{ '.','.','.','.','T','T','E','G','L'},
{ '.','.','.','.',',','N','E','L','I'}
};
char Choice[3][9] = { { 0 }, { 0 }, { 0 } };
const char WORD[] = "INTELLIGENT";
const int Len = sizeof(WORD)-1;
int Path[sizeof(WORD)-1] = { 0 };
char get(int row, int col){
if(1 > col || col > 9) return '\0';
if(1 > row || row > 3) return '\0';
if(Choice[row-1][col-1] || Matrix[row-1][col-1] == '.')
return '\0';
else
return Matrix[row-1][col-1];
}
#define toLoc(r, c) (r)*10+(c)
#define getRow(L) L/10
#define getCol(L) L%10
int search(int loc, int level){
int r,c,x,y;
char ch;
if(level == Len) return 1;//find it
r = getRow(loc);
c = getCol(loc);
ch = get(r,c);
if(ch == 0 || ch != WORD[level]) return 0;
Path[level]=toLoc(r,c);
Choice[r-1][c-1] = 'v';//marking
for(x=-1;x<=1;++x){
for(y=-1;y<=1;++y){
if(search(toLoc(r+y,c+x), level + 1)) return 1;
}
}
Choice[r-1][c-1] = '\0';//reset
return 0;
}
int main(void){
int r,c,i;
for(r=1;r<=3;++r){
for(c=1;c<=9;++c){
if(search(toLoc(r,c), 0)){
printf("YES\nPath:");
for(i=0;i<Len;++i){
printf("(%d,%d)", getRow(Path[i]), getCol(Path[i]));
}
printf("\n");
return 0;
}
}
}
printf("NO\n");
return 0;
}
I think this is what you mean..... Though it seems simpler to what you currently have been offered, so I may have misunderstood the question.
I use Numpy to reshape an arbitrary array into a single
list of letters, then we create a mask of the search term and
a copy of the input list.
I tick off each letter to search for while updating the mask.
import numpy as np
import copy
def findInArray(I,Word):
M=[list(x) for x in I]
M=list(np.ravel(M))
print "Letters to start: %s"%"".join(M)
Mask=[False]*len(Word)
T = copy.copy(M)
for n,v in enumerate(Word):
try:
p=T.index(v)
except ValueError:
pass
else:
T[p]=''
Mask[n]=True
print "Letters left over: %s"%"".join(T)
if all(Mask):print "Found %s"%Word
else:print "%s not Found"%Word
print "\n"
return all(Mask)
I=["IIIINN.LI","....TTEGL",".....NELI"]
findInArray(I,"INTEL")
findInArray(I,"INTELLIGENT")
findInArray(I,"INTELLIGENCE")
Example output
Letters to start: IIIINN.LI....TTEGL.....NELI
Letters left over: IIIN.I....TGL.....NELI
Found INTEL
Letters to start: IIIINN.LI....TTEGL.....NELI
Letters left over: II.I.........NLI
Found INTELLIGENT
Letters to start: IIIINN.LI....TTEGL.....NELI
Letters left over: II.I....T.....NLI
INTELLIGENCE not Found
#include <stdio.h>
#define ROW 1
#define COL 11
char Matrix[ROW][COL] = { { 'I','N','T','E','L','L','I','G','E', 'N', 'T'} };
char Choice[ROW][COL] = { { 0 } };
const char WORD[] = "INTELLIGENT";
const int Len = sizeof(WORD)-1;
int Path[sizeof(WORD)-1] = { 0 };
char get(int row, int col){
if(1 > col || col > COL) return '\0';
if(1 > row || row > ROW) return '\0';
if(Choice[row-1][col-1] || Matrix[row-1][col-1] == '.')
return '\0';
else
return Matrix[row-1][col-1];
}
#define toLoc(r, c) (r)*16+(c)
#define getRow(L) L/16
#define getCol(L) L%16
int search(int loc, int level){
int r,c,x,y;
char ch;
if(level == Len) return 1;//find it
r = getRow(loc);
c = getCol(loc);
ch = get(r,c);
if(ch == 0 || ch != WORD[level]) return 0;
Path[level]=toLoc(r,c);
Choice[r-1][c-1] = 'v';//marking
for(x=-1;x<=1;++x){
for(y=-1;y<=1;++y){
if(search(toLoc(r+y,c+x), level + 1)) return 1;
}
}
Choice[r-1][c-1] = '\0';//reset
return 0;
}
int main(void){
int r,c,i;
for(r=1;r<=ROW;++r){
for(c=1;c<=COL;++c){
if(search(toLoc(r,c), 0)){
printf("YES\nPath:");
for(i=0;i<Len;++i){
printf("(%d,%d)", getRow(Path[i]), getCol(Path[i]));
}
printf("\n");
return 0;
}
}
}
printf("NO\n");
return 0;
}

Resources