How to write C program that accepts user input tha

2019-08-28 05:12发布

Solution

#include <stdio.h>
#include <string.h>
 int main()
{
    char value[50];
    char *end;
    int sum = 0;
    long conv;
    while(conv != 0 )
    {
            printf("Enter a measurement and unit(Ex: 4' or 3\";0' or 0\" when done): ");
            fgets(value, 50, stdin);
            conv = strtol(value, &end, 10);
            if(strstr(value, "\'") != NULL)
            {
                    conv = strtol(value, &end, 10);
                    sum = sum + (conv*12);
            }
            else if(strstr(value, "\"") != NULL)
            {
                    conv = strtol(value, &end, 10);
                    sum = sum + conv;
            }
    }
    printf("Total: %d, %s\n", sum, "inches" );
    return 0;
}

UPDATE Still having problems with new program..unsure where to go from here. It is accepting numbers and quotes, but it keeps multiplying any number I type in by 12 when it should only do that if I enter a single quote to specify feet. UPDATE2 Here are the functions for Assembly that we should keep in mind for writing the C program:

void printStr(char *)
 Arguments:
 edi = address of null-terminated string to print
 Returns:
    Nothing

void printUInt(unsigned)
 Arguments:
 edi = Unsigned integer to print
 Returns:
  Nothing

 char getchar()
  Arguments:
  None
  Returns:
   eax = the next character

 uinsigned readUInt()
 Arguments:
 None
 Returns:
  eax = an unsigned int read from stdin.
       (eax is 0 on error)

I must write a C program which prompts the user to enter a measurement(number) and unit( ' or ", which represent feet or inches) and then prints out the Total length in inches AFTER the user enters a length of '0' which acts as a sentinel value.

This program is only needed to act as a way for me to then build an Assembly program with a similar structure. The thing is, it must be built around 4 functions that would be called to help perform some of the operations.

So my C program should be built similarly with those functions in mind. Here's what I have:

Here is my program:

UPDATED:

int main()
{
    char value[50];
    char *end;
    int sum = 0;
    long conv;
    while(conv != 0)
    {
            printf("Enter a measurement and unit: ");
            fgets(value, 50, stdin);
            conv = strtol(value, &end, 10);
            if(value[1]='\'')
            {
                    sum = sum + (conv*12);
            }
            if(value[1]='\"')
            {
                    sum = sum + conv;
            }
    }
    printf("Total: %d\n", sum);
    return 0;
}

OLD:

int main()
{
    int sum = 0;
    int value;
    char symbol;

    while(value != 1)
    {
            printf("Enter measurement and unit: ");
            scanf("%d,%d", &value, &symbol);

            if(symbol == "'")
            {
                    sum = sum + value*12;
            }
            else if(symbol == ''' )
            {
                    sum = sum + value;
            }

            sum = sum + value;
    }
    printf("Total: %d", sum);
    return 0;
}

I hope I have enough information here for someone to help me even though I know we're missing the complete functions for time being. And I know the IA32 assembly conversion is not my main question and I think I will save that for another if I get stuck, but I hope getting this High-Level language program corrected will get me going in the right direction. Thanks in advance!

标签: c linux assembly
3条回答
冷血范
2楼-- · 2019-08-28 05:42

Get the character using %c not %d. Change the line into like this.

if ( scanf("%d,%c", &value, &symbol) != 2 )
       continue;

While comparing you have to do like this,

if(symbol == '\"')
{
           sum = sum + value*12;
}
else if(symbol == '\'' )
{
              sum = sum + value;
}

Output after this,

Enter measurement and unit: 2,"
Enter measurement and unit: 3,'
Enter measurement and unit: 1,"
Total: 45
查看更多
一纸荒年 Trace。
3楼-- · 2019-08-28 05:58

When you think about writing a program that will be translated to assembly, you want to limit yourself to using calls that have a 1-to-1 correlation to the system calls available in assembly. That means leaving the high-level world of buffered input/output and using the unbuffered low-level input/output methods where you are responsible for counting each byte that goes in or out of the program. Even the low-level routines of read and write in C, provide quite a few features that you will have to handle by hand in assembly.

In order to provide a reasonable example of this low-level I/O, I've written a short example to take your input measurements in either feet or inches and keep a running total of the feet and inches entered. The code also converts any inches over 12 into feet accordingly. This example provides a good approximation of the approach you will take in assembly to do the same thing. Take time to understand what each part does, and let me know if you have questions. The lower-level code you write, the longer it becomes to accomplish seemingly simple tasks. Your assembly will probably be 3-times longer.

The program expects input of the form numfeet' or numinches". So to enter 10 feet, enter 10', for 10 inches, enter 10":

#include <stdio.h>
#include <unistd.h>

#define STDINFD 0
#define STDOUTFD 1
#define newline write (STDOUTFD, "\n", 1)

#define MAXS 32

int main (void) {

    ssize_t n = 0;              /* number of characters read    */
    size_t i = 0;               /* general iteration variable   */
    size_t digits = 0;          /* digit counter                */
    char buf[MAXS] = {0};       /* buffer to hold input         */
    char *bp = buf;             /* pointer to input buffer      */
    char length[MAXS] = {0};    /* buffer to hold measurement   */
    char *p = length;           /* pointer to measurement       */
    char fbuf[MAXS] = {0};      /* buffer to hold feet          */
    char *fp = fbuf;            /* pointer to feet              */
    char ibuf[MAXS] = {0};      /* buffer to hold inches        */
    char *ip = ibuf;            /* pointer to inches            */
    unsigned feet = 0;          /* total feet entered           */
    unsigned inches = 0;        /* total inches entered         */
    unsigned num = 0;           /* general unsigned value       */
    unsigned mlt = 1;           /* place multiplier value       */
    unsigned incvt = 0;         /* inches to feet conversion    */
    char unit = 0;              /* buffer for ''' or '"'        */
    char const digit[] = "0123456789";  /* conversion string    */

    /* input prompt and labels */
    char prompt[] = "\n Enter measurement with units [feet' or inches\"]: ";
    char nlabel[] = "\n number : ";
    char ulabel[] = "\n   unit : ";
    char flabel[] = "\n   feet : ";
    char ilabel[] = "\n inches : ";

    /* write prompt to stdout */
    write (STDOUTFD, prompt, sizeof prompt);

    /* read length and unit until [CTRL+D] entered */
    while ((n = read (STDINFD, bp, 32)) != 0)
    {
        /* re-initialize values for each loop */
        bp = buf;
        p = length;
        fp = fbuf;
        ip = ibuf;
        i = 0;
        num = 0;
        incvt = 0;
        mlt = 1;
        unit = 0;

        /* parse each character read into buf */
        while (bp[i] != '\n')
        {

            if (bp[i] >= '0' && bp[i] <= '9')   /* is a digit   */
                *p++ = bp[i];

            if (bp[i] == 0x27)                  /* is a '       */
                unit = bp[i];

            if (bp[i] == '"')                   /* is a "       */
                unit = bp[i];

            i++;
        }

        /* null-terminate / decrement length pointer */
        *p = 0;
        p--;

        /* write length and unit to stdout */
        write (STDOUTFD, nlabel, sizeof nlabel);
        write (STDOUTFD, length, p - length + 1);
        write (STDOUTFD, ulabel, sizeof ulabel);
        write (STDOUTFD, &unit, sizeof unit);
        newline;

        /* convert characters in length to number */
        for (i = p - length; p >= length; p--)
        {
            num += (*p - '0') * mlt;
            mlt *= 10;
        }

        /* test unit and add to feet or inches */
        if (unit == '"')
            inches += num;
        if (unit == 0x27)
            feet += num;

        /* convert inches > 12 to feet */
        if (inches > 12)
        {
            incvt = inches / 12;
            inches -= incvt * 12;
            feet += incvt;
        }

        /* write label for total feet to stdout */
        write (STDOUTFD, flabel, sizeof flabel);

            /* determine number of digits in feet */
            i = 1;
            digits = 0;
            while (feet >= i && (1UL << 32))
            {
                digits++;
                i *= 10;
            }

            /* convert number to characters in feet buffer */
            num = feet;
            fp += digits - 1;
            while (fp >= fbuf)
            {
                *fp-- =  digit [num % 10];
                num /= 10;
            }

        /* write the number of feet and label for inches to stdout */
        write (STDOUTFD, fbuf, digits);
        write (STDOUTFD, ilabel, sizeof flabel);

            /* determine number of digits in inches */
            i = 1;
            digits = 0;
            while (inches >= i && (1UL << 32))
            {
                digits++;
                i *= 10;
            }

            /* convert number to characters in inches buffer */
            num = inches;
            ip += digits - 1;
            while (ip >= ibuf)
            {
                *ip-- =  digit [num % 10];
                num /= 10;
            }

        /* write the number of inches and newline to stdout */
        write (STDOUTFD, ibuf, digits);
        newline;

        /* zero all buffers */
        for (i = 0; i < MAXS; i++)
            buf[i] = length[i] = fbuf[i] = ibuf[i] = 0;

        /* prompt for next input ([CTRL+D] to quit) */
        write (STDOUTFD, prompt, sizeof prompt);

    }

    newline;

    return 0;
}

Example / Output

$ ./bin/read_measurement

 Enter measurement with units [feet' or inches"]: 10"

 number : 10
   unit : "

   feet :
 inches : 10

 Enter measurement with units [feet' or inches"]: 10'

 number : 10
   unit : '

   feet : 10
 inches : 10

 Enter measurement with units [feet' or inches"]: 4"

 number : 4
   unit : "

   feet : 11
 inches : 2

 Enter measurement with units [feet' or inches"]:

Update to your high-level code

If you are going to continue to use the high-level functions, then make use of the fact that end already points to the next character following the number after you call strtol. e.g.:

while (printf ("\nEnter a measurement and unit: ") && fgets (value, 50 - 1, stdin))
{

    errno = 0;
    conv = strtol (value, &end, 10);

    if (errno == 0 && value != end)
    {
        if (*end == '\'')
            sum = sum + (conv*12);
        else if (*end == '\"')
            sum = sum + conv;
        else
            printf ("error: no unit following number.\n");
    }
    else
        printf ("error: no value read.\n");
}
查看更多
别忘想泡老子
4楼-- · 2019-08-28 06:04

I see several bugs in your "updated" code: one on nearly every line.

int main()

Header files missing. (It's much easier for us to help you if you give us a complete program that can be compiled and tested without modification.)

Should be int main(void); empty argument parentheses are poor style.

{
    char value[50];
    char *end;
    int sum = 0;

This is fine.

    long conv;
    while(conv != 0)

Use of uninitialized variable. I would write a do-while loop instead.

    {
            printf("Enter a measurement and unit: ");

Unnecessary use of printf (better fputs since no formatting is required).

            fgets(value, 50, stdin);

If you have getline, use it.

            conv = strtol(value, &end, 10);

It is necessary to set errno to zero manually before any use of the strto* functions, because some errors are only visible that way.

            if(value[1]='\'')

Your immediate problem is here. There are three bugs on this line:

  • You haven't checked whether strtol returned an error.
  • value[1] is the second character read by fgets, not the character immediately after the number. The character immediately after the number is end[0].
  • Comparison uses ==, not =; this condition is assigning '\'' to value[1] and then testing whether '\'' is nonzero; since '\'' has to be nonzero, the body of the if-statement always executes, which is why you are seeing it always multiply by 12. This would have been more obvious if you had put spaces around the =. If you had run the compiler with warnings enabled, it would have told you about this mistake.
            {
                    sum = sum + (conv*12);
            }

ok

            if(value[1]='\"')

Same problems as the earlier if-statement; should be else if.

            {
                    sum = sum + conv;
            }

Missing else clause here in which you report an error because the character after the number was neither ' nor ".

Missing check for junk input after the number and unit specifier.

    }
    printf("Total: %d\n", sum);
    return 0;
}

the rest is fine


You probably could also use a primer on how to check whether strtol returned an error. This is a little finicky, because strtol has no special return value that indicates an error; if an error happened, it will either set errno, or not consume any characters. Unfortunately, when an error did not happen, it does not necessarily clear errno, so you have to do it yourself:

errno = 0;
conv = strtol(value, &end, 0);
if (end == value || errno) {
    fputs("Invalid number, or no number entered\n", stderr);
    continue;
}
查看更多
登录 后发表回答