My C program has turned into a monster

  • Thread starter Jamin2112
  • Start date
  • Tags
    Program
In summary: We have gone past the end of the args array */}else /* If current character is not a digit */ {plo = args;nrp = 1;}}}}In summary, the program accepts a string as input and attempts to find an equation that can be used to calculate the given integer. If no equation is found, the program returns -1. If there is only one argument, it is assumed to be the input string. Otherwise, the program parses the input using the parse_input function
  • #1
Jamin2112
986
12
I started making a program with the following prompt (For privacy purposes, I'm posting it as an image).

2vwxrh1.jpg


Yes, it's a useless program; I'm making it for fun.

I started out with what I thought were some nice implementations of helper functions:

Code:
int index_of (char * str, char c)

{

/* Returns the index of the first instance of 

  character c in the character array str. If

  none is found, returns -1.

*/

    int i = 0;

    while (str != '\0')

    {

        if (*str == c)

        {

            break;

        }

        else

        {

            ++str;

            ++i;

        }

    }

    return str == '\0' ? -1 : i;

}

int parse_int (char * cp, int * i)

{

/*  cp: Pointer to a character array that is a base-10 string representation of an integer

    i: Pointer to an integer which will store the output of the parsing of cp
    Returns the number of characters parsed.
*/

    int n = 0;

    *i = 0;

    while (cp!= '\0')

    {

        char c = *cp;

        if (c >= '0' && c <= '9')

        {

            n = n * 10 + (c - '0');

        }

        else

        {

            break;

        }

       

        ++cp;

    }

   

    return n;

}
int bin_op (int a, char oper, int b)

{

/* Returns 

   

    a oper b
  where oper is defined as in the specs.

     

*/

    int c;

    switch (oper)

    {

        case '|':

            c = a | b; break;

        case '*':

            c = a & b; break;

        case '^':

            c = a & b; break;

        default: /* Never happens */

            ;

    }

    return c;

}

After that it went all downhill ... I realized I'm doing something wrong after I go halfway through writing my master function.

Code:
int parse_input (char ** args, int args_len, int * output, char * err)

{

/*       args: Command-line parameters

    args_len: Number of command-line parameters

      output: Evaluation of the equation

          err: Error message

*/

    if (args_len < 2)

    {

        str_cpy("No equation provided.", err);

        return -1;

    }

    char * pcc = args[1]; /* Pointer to current character */

    char cc = *pcc; /* Current character */

    char * plo = NULL; /* Pointer to last operator */

    int nnrp = 0; /* Net number of right parantheses */

    while (cc != '\0')

    {

        if (cc >= '0' && cc <= '9') /* If current character is a digit */

        {

            int pi = 0; /* Parameter index */

            pcc += parse_int(pcc, &pi);

            if (pi > (args_len - 2))

            {

                sprintf(err, "Index %d is out-of-bounds", pi);

                return -1;

            }

            int pv; /* Value at parameter pn */

            if (parse_int(args[pi], &pv) > 0)

            {

                if (plo == NULL)

                {

                    *output = pv;

                }

                else

                {

                    *output = bin_op(*output, *plo, pv);

                }

            }

            else

            {

                sprintf(err, "Parameter %d is not an integer", pv);

                return -1;

            }

           

        }

        elseif (index_of(ops, cc) > -1) /* If current character is an operator */

        {

            if (pcc == args[1]) /* If the current character is the first character */

            {

                sprintf(err, "Expression cannot begin with %c", cc);

                return -1;

            }

            elseif (pcc == (args[1] + sizeof(args[1])/sizeof(char *))) /* If the current character is the final character */

            {

                sprintf(err, "Expression cannot end with %c", cc);

                return -1;

            }

            else if ((*(pcc - 1)) < '0') && (*(pcc - 1) > '9')) /* If the previous character is not a digit */

            {

                sprintf(err, "Operator %c must be preceded by a digit, cannot be preceded by %c", cc, *(pcc - 1)));

                return -1;

            }

            else/* The current character is an operator preceded by a digit */

            {

                *plo = cc;

            }

        }

        else if (cc == '(')

        {

            if (pcc == (args[1] + sizeof(args[1])/sizeof(char *))) /* If the current character is the final character */

            {

                sprintf(err, "Expression cannot end with %c", cc);

                return -1;

            }

            else if (

            {

               

            }

            else

            {

                ++nnrp;

            }

        }

        else if (cc == ')')

        {

          // ...

            --nnrp;

        }

        ++pcc;

    }
Anyways, can someone please criticize me in the most condescending way possible; and if you're feeling nice, maybe give me an outline of how to better approach this problem?
 
Technology news on Phys.org
  • #2
Well if I were writing such a program and wanted to use the same characters you chose for logic operators then I'd have the program run and provide a prompt. The problem is that * and other characters may be processed by the command shell you're using and so wouldn't t be passed to your program at all.

Next I would allow for infix notation so you don't need to write the expression followed by the data.
In a sense you're writing a command line calculator program where users could enter 0001+1000 and the program would respond 1001.

what you need to write is a line parser that breaks up things into tokens and then processes them using a data stack and an operator stack that is if you want to support parentheses.
 
  • #3
jedishrfu said:
Well if I were writing such a program and wanted to use the same characters you chose for logic operators then I'd have the program run and provide a prompt. The problem is that * and other characters may be processed by the command shell you're using and so wouldn't t be passed to your program at all.

True.

Next I would allow for infix notation so you don't need to write the expression followed by the data.
In a sense you're writing a command line calculator program where users could enter 0001+1000 and the program would respond 1001.

The whole point of the problem is to implement a calculator that uses postfix notation.

what you need to write is a line parser that breaks up things into tokens and then processes them using a data stack and an operator stack that is if you want to support parentheses.

I don't see why I can't do what I'm trying to do, which is an algorithm like

Code:
parse_equation:

   Have an integer k that will be the result.   

   For each character character c in a string S {

      if c is a digit, run a parse_int routine that reads a string beginning at c into an int i and meanwhile increments c. Afterwards, update k by k=k$i where $ is the last operator; if there is no last operator, then i is the first int parsed, so set k=i;

      if c is an operator, store that as the last operator.

      if c is a right-facing parenthesis, increment c until reaching the parenthesis that closes it. Run parse_int on the string inside the parenthesis and $ the result to k, where, again, $ is the last operator

    }

    Return k;
 
  • #4
Here's a better look at what I have so far. Remove the * in https://github.com/j**a***m******k***in/**cs**L**o**g**ic
 
Last edited by a moderator:
  • #5
I'll try to be as 'condescending' as possible.

As I took the prisoner downstairs, I said "You should leverage the standard C library. Your function index_of is very similar to strchr. The function parse_int is very similar to atoi. The rest of the code doesn't seem unreasonable for a hand written parser."

Get it? prisoner = con. downstairs = descending. I love Tom Swifty's.
 
  • #6
ScottSalley said:
I'll try to be as 'condescending' as possible.

As I took the prisoner downstairs, I said "You should leverage the standard C library. Your function index_of is very similar to strchr. The function parse_int is very similar to atoi. The rest of the code doesn't seem unreasonable for a hand written parser."

Get it? prisoner = con. downstairs = descending. I love Tom Swifty's.

Standard libraries are for chumps. My mottos are:

  • Always reinvent the wheel
  • Micro-optimization is the greatest good
  • Cleverness over readability
 
  • Like
Likes ellipsis and jedishrfu
  • #7
Unfortunately the real world doesn't like wheel inventors unless the wheel is vastly superior to what is in use now.
 
  • #8
If you want to do this cleanly (i.e. without a monstrous program), take a look at the shunting-yard algorithm. This allows you to convert infix notation logical expressions to reverse polish notation, which is much more efficient to parse (using a stack data structure). The conversion and execution thereby only takes two passes through, which results in O(n) asymptotic complexity.

To clarify: You are taking in an expression is infix (as in 2+5), yes? Because postfix (aka reverse polish notation) does not have parentheses.
 
  • #9
ellipsis said:
If you want to do this cleanly (i.e. without a monstrous program), take a look at the shunting-yard algorithm. This allows you to convert infix notation logical expressions to reverse polish notation, which is much more efficient to parse (using a stack data structure). The conversion and execution thereby only takes two passes through, which results in O(n) asymptotic complexity.

To clarify: You are taking in an expression is infix (as in 2+5), yes? Because postfix (aka reverse polish notation) does not have parentheses.

That will be my next implementation.

Just finished writing my first implementation: htt ps:/ /gi th ub.com /jam ki n/c sLo gic
 
  • #10
That's good. Also, you might want to note the difference between "logical" and "bitwise" operations. Logical operations perform on boolean values, while bitwise operations perform on sets of booleans (numbers).

I took a look at the repo, by the way.
 
Last edited:

1. Why is my C program taking so long to compile?

There could be several reasons for this. One possibility is that your program has grown too large and complex, causing the compiler to take longer to process it. Another possibility is that there are errors in your code that the compiler is struggling to resolve. It is also possible that your computer's resources are limited, causing the compilation process to take longer.

2. How do I fix errors that keep popping up in my C program?

The first step is to carefully examine the errors and try to understand what is causing them. Common mistakes in C programming include syntax errors, missing semicolons, and incorrect data types. Use a debugger or print statements to help identify the source of the errors. If you are still having trouble, consult online resources or seek help from a more experienced programmer.

3. My C program used to work, but now it crashes or produces incorrect results. What could be causing this?

This could be due to a change in your code or in the environment in which your program is running. Some common causes of program crashes include memory leaks, out-of-bounds array access, and infinite loops. Make sure to thoroughly test your code and check for any recent changes that may have caused the issue.

4. How do I improve the performance of my C program?

To improve performance, start by optimizing your algorithms and data structures. Consider using more efficient data types and minimizing memory usage. You can also use profiling tools to identify and address any bottlenecks in your code. Additionally, make sure to close any unnecessary files or resources to free up memory and improve performance.

5. I'm overwhelmed by the complexity of my C program. How do I make it more manageable?

One approach is to break your program into smaller, more manageable functions or modules. This allows you to focus on one specific task at a time and makes it easier to debug and maintain your code. You could also consider using comments and descriptive variable names to make your code more readable. Lastly, consider using design patterns or other programming techniques to help organize and simplify your code.

Similar threads

  • Programming and Computer Science
Replies
29
Views
4K
  • Programming and Computer Science
Replies
7
Views
1K
  • Programming and Computer Science
Replies
4
Views
737
  • Programming and Computer Science
Replies
32
Views
2K
  • Programming and Computer Science
3
Replies
75
Views
4K
  • Programming and Computer Science
3
Replies
89
Views
4K
  • Programming and Computer Science
Replies
17
Views
1K
  • Programming and Computer Science
Replies
2
Views
2K
  • Programming and Computer Science
Replies
3
Views
3K
  • Programming and Computer Science
Replies
6
Views
2K
Back
Top