Emma (hearthand) wrote in algorithms,
  • Mood: aggravated

C

I'm finding C difficult to understand. I'm working using two books: C in a Nutshell and I'm referencing with Comprehensive C (which is old but it was free.) The problem I'm trying to solve is to create a Reverse Polish Notation calculator. I'm using an array as a stack and the basic principle is:
for input (from command prompt) 2 1 +
Push 2 on the stack. Push 1 onto the stack. Meet operator, pop two and then push answer onto the stack.

But I'm having problems with my main method, particularly with the C syntax. This is my main method so far:

/*
 * I need a way for the program to read input separated by space, where a space will
 * indicate the end of a value. For example: 23 3 is the input twenty three and three,
 * not: two, three, three.
 *
 * When an integer operand is encountered, it will be pushed onto the stack. An operator
 * will cause two items of the stack of be popped then a push of the answer.
    argc = SIZE OF THE ARRAY
    argv = Array of strings that represents the command line entered.
 */

int main (int argc, char *argv)

{
    int i;
    for (i = 1; i < argc; i++)
    {
        if (x argv = int)
        {
            push(int x)       

                //http://www.cppreference.com/stdstring/isdigit.html
                //http://www.cppreference.com/stdstring/atoi.html
    }
}

The hyperlinks are a link to two methods from the library that I need to use: isdigit() and atoi(). Because the input is being entered from the command prompt it's my understanding that a character and an integer cannot be differentiated simply by their bit pattern. What I need to do with the input is take the "string", convert it to an integer and then check to see if it is an integer or not.

Now, in Java I'd do something like x.isdigit().atoi() but... gah! There's a lot of true/false requirements in there and I don't think I actually fully understand exactly what I'm trying to do.

This is what I'm planning to do, in English:

If ( x is a character) {
    either return 0 as value
   or set next item to memory location [x]
}
if (x is an operator) {
   POP two from the stack
   use operator on two operands
   Push answer onto the stack again
      //error checking for condition that only one value has been pushed onto stack
}
//otherwise, fall through assuming that x is an integer
convert x into an integer using atoi()
Push (x)

TADA!

I'm planning on using if for error checking and converting everything else to case statements instead. I'm use to programming in java, though, so I'm scared that I'm java-ing too much :/

Advice? Kicks? Clarifications?
  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 55 comments

lord_jim

March 28 2008, 16:01:46 UTC 6 years ago

I'm at work and don't have time to debug your code, and I'm a bit rusty when it comes to C. I did want to recommend a book for you. I am many many man C programmers learned C from The 2 guys who developed C. If my Amazon link didn't work, the book is called "C Programming Language (2nd Edition)" and it is written by Brian W. Kernighan and Dennis M. Ritchie. If you've heard of K&R C, well that's the K and the R that developed C in the first place. That book is, in my not so humble opinion a excellent reference. There is no fluff in that book. It has a lot of examples and several may help you out. I'm sorry if this seems like an ad for the book, but it really is an excellent reference.

There are standard library functions that will do the work you are describing. atoi is a standard library function. You'll want to include stdlib.h as that defines the function. There are also some standard functions that can tell you data types including isdigit. Those are defined by the ctype.h header file. Good luck with this!

hearthand

March 28 2008, 16:19:22 UTC 6 years ago

Thank you for your comment! C programming language was recommended to me by the community when I asked for a C book suggestion, but later I discovered that "C in a Nutshell", a reference book, is the core course text book and came highly recommended. On reflection, I wish I'd bought the C book written by the two developers, I struggle with syntax more than designing code and a reference book isn't really helpful if you don't know a certain library function exists in the first place.

The code I posted is likely to change over and over again since I am activly working on it just now. I've just posted my recursive version of what I want the main method to do. I might use the case tool instead of so many if statements, since apparently our lecturer frowns upon the evil that is IF. It also isn't the whole program, but only the main method and the documentation over that main method, if I run into problems when I actually compile it (using gnu) then I'd be more than happy for help when debugging it... maybe I should start debugging now... :)

I've got plans to use atoi, isdigit (though apparently I shouldn't use isdigit, but atof instead?) and strlen. :/

ginaspider

March 28 2008, 16:24:22 UTC 6 years ago

Maybe there's a better way to do this, but I find this will work:
char int_buffers[MAX_BUFFERS][MAX_SIZE];
int i,buffer_number,buffer_offset;
buffer_number = -1;

for(i=0;;i++) {
 if(mystring[i] == 0) break;
 if(mystring[i] == ' ') {
  if(buffer_number > -1)
   int_buffers[buffer_number][buffer_offset+1] = 0; /* put terminators on */
  buffer_offset = 0;
  buffer_number++;
 }
 if(mystring[i] < '9' && mystring[i] > '0') { /*ascii 0123456789 */
  if(buffer_number == -1) { buffer_number++; buffer_offset = 0; }
  int_buffers[buffer_number][buffer_offset++] = mystring[i];
 }
}


This should pull out all the integers from a string and stick them in *int_buffers[]
if buffer_numbers is still -1 we haven't found any numbers.

I just tested this and it seems to work.

ginaspider

March 28 2008, 16:28:50 UTC 6 years ago

sscanf is also very nice.

hearthand

March 28 2008, 16:42:50 UTC 6 years ago

We're reading input from the command prompt, would sscanf work on command prompt input?

My program so far (minus the main that I've posted above) is this (without documentation)

########################################################
#include
[Error: Irreparable invalid markup ('<stdio.h>') in entry. Owner must fix manually. Raw contents below.]

We're reading input from the command prompt, would sscanf work on command prompt input?

My program so far (minus the main that I've posted above) is this (without documentation)

########################################################
#include <stdio.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


int top; /*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 bottomstack; /*Pointer for the location of the bottom of the stack (0)*/

int stack[maxstack] /*sets the array stack equal of the maximum value of the stack*/


void push(int x)
{
stack[top] = x;
top ++;
}

int pop ()
{
return (popped[top]);
top --;
}

hearthand

March 28 2008, 16:46:40 UTC 6 years ago

what's the '9' for? My lecturer had mentioned the use of '9' in solutions he'd already been mailed (from the more enthusiastic members of the class ;)) but he didn't clearly explain it (although he later went on to mention using q instead of ? and e instead of !)

:) Thank you for sharing your solution, it's given me some ideas!
I'll be updating the main method in my post soon with my own, I'm fighting with CASE just now :/

ginaspider

March 28 2008, 16:52:50 UTC 6 years ago

Yeah sure. Typically I find you have put too much work into making thea input of sscanf sane that it isn't worth it. But, fscanf(stdin, "%d %d %d", &a,&b,&c) will pull out three integers from input. Well, I don't know what he's talking about but it's ascii '9'. An integer character would be between ascii '0' and ascii '9'.

So, I don't understand. What do you think he meant by using q instead of ? and e instead of !?

Keep us posted

hearthand

March 28 2008, 17:00:54 UTC 6 years ago

I honestly have no idea about the significance of ? and !. Come to think of it, some of the other programmers on my course use Unix OS on their laptops; are ? or ! commands in a unix command prompt, that could be why they're substituting it with e and q. I just tried both in a MS Command Prompt, but neither did anything fun. Your 9 triggered something in my memory: I remember someone had put 9 in as a limit so their program could only add numbers 0 through 9 (in an attempt to error check and restrict negative numbers and take in one number at a time) but they were later told that their program must deal with all real numbers or cope with them. I've been reading about sscanf in the standard libary section of the reference I have... yikes! You're right! Perhaps this code: for (i = 1; i < argc; i++) will suffice to plod along my input :) (since bit 0 holds the program name I'm compiling) :)

lightning_rose

March 28 2008, 16:55:21 UTC 6 years ago


Pay no attention to the above two posts from ginaspider. Neither one has anything to do with your assignment and will only lead to more confusion.

hearthand

March 28 2008, 17:02:02 UTC 6 years ago

Thanks. You're right that they did confuse me, but I had assumed that it was because I tend to litter my own code with double the documentation to each line :)

lightning_rose

March 28 2008, 16:52:42 UTC 6 years ago


You're making the common newbie mistake of trying to write your entire program at once. Don't do this, it doesn't work. Take a deep breath and slow down.

Start with the first problem, which is you've never before worked with command line arguments. So write a program that does nothing but echo each argv[] on a new line.

Your use of argc in the for-loop is correct, so inside that loop use the printf() function to print each string in the argv[] array.

When that's done move on to the next problem which is differentiating a numeric string from an operator string.

For posting code without losing the formatting, you can use this tool:
http://www.lightning-rose.com/projects/txt2html.htm

hearthand

March 28 2008, 17:06:09 UTC 6 years ago

*blushes* I do have a tendancy to jump into a program and hack away at the code until it works. It's my approach to java most of the time, at least. Recently thre'd been a lot of talk from the older/experienced programmers on my course who are complaining that our course has been made inappropriatly difficult because we aren't actually taught proper programming techniques of planning, desinging, pseudocoding and FINALLY coding (I don't even know the right order for doing those things, actually...)

I think you're right, I should back down because I have never taken input in from a command line before to do anything with it - and that's part of my problem because I keep worrying about how the program will know it's the command line and zomg- suddenly I've forgotten everything else.

I'll comment again once I've done the program to take in input then differentiate ;)

hearthand

March 28 2008, 17:27:22 UTC 6 years ago

I would like you to know, while I'm printing indexes instead of the actual input, that I dislike programs that compile but don't work. ;)

lightning_rose

March 28 2008, 17:42:27 UTC 6 years ago


If they compile and don't blow up when executed, then they work.

They always do what you say, but they may not do what you want. :)

As relaxing noted below, your above declaration of main() is incorrect. I missed that when I first read your code.

It should be one of the following:

main( int argc, char **argv )

or

main( int argc, char *argv[] )

I think it will be less confusing to you if you use the latter.

humanplacebo

March 28 2008, 17:35:09 UTC 6 years ago

I agree on the basic approach. Write the tiniest testable bit of code that you can, then try it out and see how it works.

From your post, it looks like there's two categories of issue:

1. Figuring out the correct algorithm. Your pseudocode is pretty close, and you seem to have no problems figuring that part out. (The way you've written it, you can get rid of the Push in the operator block)
2. Particulars of C syntax. I don't feel like it's cheating to offer advice here:

Let's look at getting the command line arguments from argv.

One of the common ways of getting at argv are by addressing it as an array, like:
  int ii;
  for(ii = 1; ii < argc; ii++) {
    printf("%s\n", argv[ii]);
  }

Notes:
- I start at 1 instead of 0, because argv[0] contains the name of the program itself that was used on the command line.
- I use "ii" instead of "i" for simple iterators! It's short, visually distinct and easy to search for. (ii, jj, kk, etc, rarely appear in other places. That's not a C thing, just a programming practice stolen from a very smart professor.)

Another common way is to dereference argv as a pointer, then increment argv to point at the next string from the command line:
  int ii;
  argv++;
  for(ii = 1; ii < argc; ii++) {
    printf("%s\n", *argv);
    argv++;
  }

Notes:
- I increment argv once before the loop to skip the program name.

This code can be condensed by doing the dereference and the increment together:
  int ii;
  argv++;
  for(ii = 1; ii < argc; ii++) {
    printf("%s\n", *argv++);
  }

Or condensed more by using a preincrement:
  int ii;
  for(ii = 1; ii < argc; ii++) {
    printf("%s\n", *++argv);
  }


Okay, next up, string to integer conversion! (The short answer, you'd be fine using either sscanf or atoi)

humanplacebo

March 28 2008, 17:51:18 UTC 6 years ago

Yeah, either atoi or would work. They work slightly differently, though. Try this little program with numeric and non-numeric input and see how it works:

int main(int argc, char *argv[]) {
  int ii, a, b, x;
  argv++;
  for(ii = 1; ii < argc; ii++) {
    a = atoi(*argv);
    x = sscanf(*argv, "%d", &b);
    printf("atoi result:    %d\nsscanf result:  %d\nsscanf returns: %d\n\n", a, b, x);
    argv++;
  }
}

Oh, and the reason I'm okay with posting code here for someone else's homework assignment is because you could get this in 3 seconds with a Google search, but I think it's better to know where your advice is coming from. (Although, being in Alaska, I'm pretty safe from retribution if I give you bad advice!)

hearthand

6 years ago

humanplacebo

6 years ago

relaxing

6 years ago

pstscrpt

6 years ago

hearthand

6 years ago

humanplacebo

6 years ago

hearthand

6 years ago

hearthand

6 years ago

hearthand

6 years ago

hearthand

6 years ago

relaxing

6 years ago

hearthand

6 years ago

relaxing

6 years ago

hearthand

6 years ago

relaxing

6 years ago

hearthand

March 28 2008, 17:52:57 UTC 6 years ago

My solution to the problem is this:


int main (int argc, char **argv)
{
int i;
for (i = 1; i < argc; i++)
{
printf("%s\n",argv[i]);
}
}

it returns everything as you put it. From what I've read in my reference book, it considers everything to be a string.

Onto string integer conversions *marches onward* :)

Do you mean, in your use of ii, that you use ii when you're using ii as an increment instead of i because you recognise ii as an increment easier and it differentiates it from, say, if you were saying

a = 1
for (i = a; i < argc; i++){
z = s + d
//the java in me says "return z" here ;)
}

humanplacebo

6 years ago

relaxing

March 28 2008, 17:14:51 UTC 6 years ago

the prototype for main() is
int main (int argc, char **argv)

the extra star is important because it means you have not just a c string, but an argc-length array of strings, each containing an operand or operator.

hopefully you know how to index that array ( argv[i] )

isdigit and atoi are just functions, so call them like you would call any c funtion.

relaxing

March 28 2008, 17:22:37 UTC 6 years ago

another gotcha to look out for is that the first string in the argv array will be the name of the executable.

relaxing

March 28 2008, 17:23:25 UTC 6 years ago

i see you already know this :)

humanplacebo

March 28 2008, 17:39:42 UTC 6 years ago

Marginally more newbie friendly might be:

int main(int argc, char *argv[])


I'm ambivalent about that though.

hearthand

March 28 2008, 17:46:41 UTC 6 years ago

I'm assuming at "[]" universally means "An array."

Why are you making argv an array?

lightning_rose

6 years ago

hearthand

6 years ago

relaxing

6 years ago

lightning_rose

6 years ago

relaxing

6 years ago

hearthand

6 years ago

relaxing

6 years ago

hearthand

6 years ago

hearthand

6 years ago

humanplacebo

6 years ago

hearthand

6 years ago

relaxing

6 years ago

hearthand

6 years ago

relaxing

6 years ago

hearthand

March 28 2008, 17:45:45 UTC 6 years ago

I absolutely love you! I'm following lightening_rose's advice, and making programs that do simple things, like printing out input entered in the command prompt and it didn't work and and and I realised that I wasn't indexing the array (one error) and my char **argv was also a problem.

:D

Thank you!

And, since I'm proud of myself for debugging (err... almost) my own code and writing my first working C program, you may smile and praise me:

#include
[Error: Irreparable invalid markup ('<stdio.h>') in entry. Owner must fix manually. Raw contents below.]

I absolutely love you! I'm following <lj user="lightening_rose">'s advice, and making programs that do simple things, like printing out input entered in the command prompt and it didn't work and and and I realised that I wasn't indexing the array (one error) and my char **argv was also a problem.

:D

Thank you!

And, since I'm proud of myself for debugging (err... almost) my own code and writing my first working C program, you may smile and praise me:

#include <stdio.h>

/*
* This is a simple program that will take input from the keyboard and then
* print each line of input to screen.
*/

int main (int argc, char **argv)
{
int i;
for (i = 1; i < argc; i++)
{
printf("%s\n",argv[i]);
}
}

relaxing

March 28 2008, 18:09:04 UTC 6 years ago

Very good!

leonardo_m

April 1 2008, 19:14:07 UTC 6 years ago

A suggestions is to work in stages, that is to process input, creating a data structure of the filtered input, and then process that data structure, etc.
Another possible suggestion is to use a different language to create a working prototype, like Python (or even Java).