Emma (hearthand) wrote in algorithms,

  • Mood:


Edit: Error was located and corrected. I love how programming can turn programmers temporarily blind :) I'll leave it here in the hope that perhaps others with the same problem can find it and think "OOOOooooOooh" before publically admitting to a community that they can't keep track of their pointers. :)

Thank you all for your help to my previous post! I've started to pick up C syntax really quickly since, and I've been integrating my two programs; the one with the functions to push, pop and create arrays, with the program lightning_rose suggested that I should write. So far my array seems to work and I'm sure that my push function is working, but when I ask it to print the contents of the stack, it prints 0. My aim isn't to iterate down the entire array, but to print that they've been pushed once they've been pushed.

Here is the buggy bit - where I expect the error is:

/* else, it will be an integer.*/ else { int temp = atoi(argv[i]); push (temp); //int i = 0; printf("Stack: %d", stack[top]); //printf("Integer: %d\n",atoi(argv[i])); }

/* * **** HISTORY ***** * * Filename: test.c * Synopsis: test * * This is a simple program that will take input from the keyboard and then * print each line of input to screen. * Version 0.1 - Program simply returned a string of characters that had been * entered using printf. * version 0.2 - program differentiated between a string of characters and an * integer. * version 0.3 - Fixed a bug in the code that caused a 0 integer to be printed * after characters. Originally believed it to be a null byte, later discovered * that it was, in fact, a flaw in my if statements since I hadn't used else. * the use of else and else if in the testing area of the program are important * so that characters aren't printed as characters then passed down to be converted * into integers. * version 0.4 - program began to differentiate between characters, an operand * and the specific operators +, -, /, x and =. I was able to tell that the * differentiation had been made by asking the program to print out which each * was, for example: If I had entered: test 1 a + the program would output: * Integer: 1, Character: a, Symbol +. * version 0.5 - Array was defined from code that had been written in p3.c which was * written at an earlier date. This is where p3.c and test.c began to merge as * the final solution to p3.c with p3.c merging into test.c. */ #include <stdio.h> #include <string.h> /* * define is used to make modification of each easier. It is also good for readability. * Characters A - D will be assigned values that the user wishes to store so that they * can later be used by, for example, 2 A +. */ #define stack empty #define MemoryA A #define MemoryB B #define MemoryC C #define MemoryD D /* * I need to define my array that will be used in a similar way to how I understand a * stack. The type of array that I will use is a fixed-length array so that the program * size will have a limit of 20 elements. * See Page 112 - C In a Nutshell */ int top = 0; /*Pointer to keep track of where the top of the stack/array is*/ //int maxstack = 20; /*Allocates the maximum value of the stack-array */ int stack[50]; /*sets the array stack equal of the maximum value of the stack*/ void push(int x); /* * The push function will push a new entry onto the stack at the stack pointer "top". * Once the entry (passed in as x) has been assigned as an element to the stack the * "stack pointer" top will then increment by one so that it is pointing to the next * free space. */ void push(int x) { stack[top] = x; top ++; } int main (int argc, char *argv[]) { int i; int j = 0; for (i = 1; i < argc; i++) { for(j=0; j < strlen(argv[i]); j++) { /*This is a test to see if a the input is a * alphabetical number. If it is, then the * program will then check to see if it is * specifically A, B, C or D. */ if (isalpha(argv[i][j])) { printf("Character: %s\n", argv[i]); } /* These tests will test to see if input is an operand*/ else if (strcmp(argv[i], "+") == 0) { printf("Symbols: %s\n", argv[i]); } else if (strcmp(argv[i], "-") == 0) { printf("Symbols: %s\n", argv[i]); } else if (strcmp(argv[i], "/") == 0) { printf("Symbols: %s\n", argv[i]); } else if (strcmp(argv[i], "x") == 0){ printf("Symbols: %s\n", argv[i]); } /* else, it will be an integer.*/ else { int temp = atoi(argv[i]); push (temp); //int i = 0; printf("Stack: %d", stack[top]); //printf("Integer: %d\n",atoi(argv[i])); } } } }
  • Post a new comment


    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 


Once you have called push(), top no longer indexes the location where the pushed item (ie temp) is stored.

To see what's on top of the stack, you should use top-1 or in push() you could increment top before storing x in stack[].

OMG! I just realised that a moment before you commented.

I've been sitting here with 5pence coins (5p = integers, 10p = "symbol" and 2p=Memory Locations A - D) and a spoon as my pointer slowly moving along my mini array and I realised that I was +1 of the entry I'd just added.

I hate that about programming: it's always the SMALLEST thing
That's pretty good so far!

Your problem is actually really simple, and I don't want to give it away, but I'll give you a hint:

Go to push( ) and try printing out the value on top of the stack before and after your push operation.

A good rule of thumb for debugging a program in a situation like this is to go to directly where you think the error is, and try printing out the value of interest before and after the computation that you think is wrong. This will often give a good idea of where your logic might be going wrong.

Try modifying push( ) as:

void push(int x)
        printf("top index = %d ; top value = %d", top, stack[top]);
        stack[top] = x;
        top ++;
        printf("top index = %d ; top value = %d", top, stack[top]);

What might be going wrong between the two printf( )s? How do the "before" and "after" values differ from what you expected them to be, and how is it related to the problem?
Like I said above, after I posted I sat down with coins and a spoon (spoon being top) and went through my program. I've drawn a little stack on a piece of paper too and soon realised where I was.

I use the "print before and after!" method in Java programs a lot, here I'm using it to make sure that the bits are doing what they're supposed to be doing . I didn't think to use it around the push() function though! I keep mixing up Java and C syntax every so often, so I'd assumed that was where I'd gone wrong in this program, and since both Java and C look right to me I'd turned to WonderfulLJ for help in my code being kicked.

I've been yelling more than just "SPIT IT OUT!" at the program. One of them being "Cannot find symbol? It's THERE you LAZY PROGRAM - I've told you what it is, I've told you where it is... how can't you find symbol... oooh...... that's why..."
I've been yelling more than just "SPIT IT OUT!" at the program. One of them being "Cannot find symbol? It's THERE you LAZY PROGRAM - I've told you what it is, I've told you where it is... how can't you find symbol... oooh...... that's why..."

It's funny because it's just so damn true... I haven't written any C for a good few years now; I must admit, I don't miss it!
I've just started "learning" C (OK, it turns out that this program is the ONLY progam I'll be writing in C. Lots of grief for nothing, say I!), but the language I'm supposed to adopt is Java. I think I prefer C over Java but that's probably because I haven't had so much grief from C simply because I've only been writing one program.

My flatmates must think I'm psychotic - the number of things I rant at my computer and times I suddenly squeal "OMG IT'S WORKIGN!!!!!!!"
Oh, absolutely. One of my housemates ran in they were so concerned. Bless him, nice to know he cared!

I actually stood up and cheered once in the computer labs when I got my algorithms coursework working. It was really cool! And super embarassing!
I always worry, in these situations that I'll give advice that either (1) the poster already knows or (2) that someone else has already given, especially since there is sometimes such a crush to help (which is, I suppose a good thing). So, I apologize if I did say something that you already knew.

There's certainly an art to debugging, and debugging is certainly more art than science; there's a lot of different ways to do it. Sometimes, the most effective ones are the ones that seem at first the most tedious. One good method when you get really stuck is to first review the procedure you drew up in your original concept and make sure it is correct -- trace it by hand, or in your head, or with a spoon if you please -- and then do the same for your code, so you can unambiguously verify that the two match, or so that you can see immediately where your code departs from the procedure you envisioned. Sometimes the problem is a correct algorithm that is incorrectly coded, and sometimes the problem is an incorrect algorithm that is correctly coded; these are the most difficult to detect (since they fail silently), but a method like this is a sure-fire way to detect them.

It's a "say what you mean" kind of thing.

Which goes right to the Java-to-C transition problem: making sure that the code says what you mean it to say.

In some ways, programming isn't that different from learning to articulate your thoughts in conversation.

A little program like this can be kind of useful if you put it together with a parser that puts normal infix expressions in whatever notation your evaluator uses. I had one of these I built for a course assignment a while ago, and I used to use it instead of OS's built-in calculator; I thought, "cool, I can type in compound expressions! The calculator won't even let me do that!"

Good luck!
Oh, don't apologise! I'm grateful that people are helping. What you said about putting printf before and after a function actually greatly helped me a short while ago when I began to implement my operator functions, for some reason my program was telling me that "2 4 +" was 4. I put printf before and after each pop() and realised that I was having another "where top is" problem. I probably wouldn't have thought of it so quickly if you hadn't pointed out that I can do it in C! You shouldn't worry about what you say when people (like me) are asking for help, I suppose if we really didn't want to be told something then we'd tell people "Oh yeah, I know this, I've tried that..." in this case, I honestly couldn't work it out and hadn't properly printf-d through the code. Hell - I was even looking at the wrong bit!

Thanks for the luck!

I've started to try and implement some error checking into it. I want the program to stop working once it detects an error (so I've started to throw in an enum of errors) using enum and switch. I know I'm supposed to use both enum and switch because my lecturer told me to, but I can't for the life of me work out HOW to "make them friends", especially when my methods to compute are all in the for-loop. :/

Programming is so frustratin!
I don't know if anyone has pointed you to these yet, but there are a number of very helpful, free resources online that might clear up some of your troubles with the technical issues. In particular, there's the C Library Reference Guide sponsored by ACM, which makes a good handbook of usage for the built-in functions and syntax of the basic structures (like switch and enum). There's also The C Book which takes a much more instructive tone and is targeted much more toward people trying to learn C for the first time.

One (but certainly not the only) way that you might use enum and switch to enforce error checking would be to have your inner for loop set the value of a flag and then use that value as the condition for a subsequent switch in the outer loop, as:

enum {OK, ERR1, ERR2};

int errflag;

for( each string in the args ){

    errflag = OK;

    for( each character in the string ){

        do stuff;

        if( one kind of error occurred){
            errflag = ERR1;

        else if (a different kind of error occurred){
            errflag = ERR2;
    } /*end inner for*/


        case OK :
            do stuff;

        case ERR1 :
            do error handling stuff;

        case ERR2 :
            do other error handling stuff;

        default :
            or something weird happened;
    }/*end switch*/

} /*end outer for*/

Of course, this isn't the whole solution, and there are certainly other -- maybe even better -- ways it could be done. Handling errors and effectively propagating signals through the program is a very common type of problem with a lot of very interesting and creative possible solutions.

Programming can be frustrating, but that's usually when it feels like you don't know where you're going or like you don't have a way to get there. Once you get the hang of it, you can (I know I'll sound like a total nerd for saying this) have a lot of fun. The first time I took a programming course, I hated it and cursed it's name, and swore up and down I would rather be a coal miner in a crooked turn-of-the-Twentieth-century mine than a computer programmer. "What the hell does "Segmentation Fault" mean? Fuck Unix! YOU HEAR THAT? FUCK UNIX!" Now I work as a computer programmer, and I love my job. Sometimes it takes a little time to figure out how you feel about it -- sometimes you need a while to get up to speed -- but it is indeed one of those things you either love or hate.

Don't let the technical details discourage you too much. If you can get the hang of them, things go a lot more smoothly. Don't lose hope!
You've been bit by the old "off by one" bug. Speaking as a former systems tester, I can assure you that this is easily the most common bug in all of programming-dom, so no need to feel silly.