简体   繁体   中英

C, using argv[] for command line arguments

I'm having trouble with this program, it's working perfectly when I use stdin but when I modify it to get characters from the command line it doesn't. I know I'm doing something wrong but don't know what, any help would be greatly appreciated.

Description and code:

/* Program prints the date in this form: September 13, 2010
    allow the user to  enter date in either 9-13-2010 or 9/13/2010  
    format, otherwise print 'error'  */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *month(int m)
{
    char *months[]={"January","February","March","April","May",
                "June", "July","August","September","October",
                "November","December"};
    return months[m-1];
}

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

    int m=0,d=0,y=0;

    FILE *fp;

    if((fp=fopen(argv[1],"rb")) == NULL)
    {
        fprintf(stderr,"Couldn't open the file. ");
        exit(EXIT_FAILURE);
    }


    printf("Type a date (mm-dd-yyyy) or (mm/dd/yyyy): \n");

    if(fscanf(fp,"%d%*[/-]%d%*[/-]%d",&m,&d,&y) != 3)  //store characters in variables
        {
            fprintf(stderr, "Not properly formatted.");
            exit(EXIT_FAILURE);
        }

    printf("%s %2d, %4d",month(m),d,y);

    return 0;
}

Input:

01/30/1990

Output:

Couldn't open the file.

I modified your program to fix the issue you were having (and to fix some undefined behaviour , or "UB" for short), but only that:

#include <stdio.h>
#include <stdlib.h>

const char *month(int m) {
    const char const *months[] = {
        "January", "February", "March", "April",
        "May", "June", "July", "August",
        "September", "October", "November", "December",
    };

    if (1 <= m && m <= 12) {
        return months[m - 1];
    } else {
        return NULL;
    }
}

int main(int argc, char *argv[]) {
    int m = 0, d = 0, y = 0;

    if (argc == 2) {
        if (sscanf(argv[1], "%d%*[/-]%d%*[/-]%d", &m, &d, &y) != 3) {
            fprintf(stderr, "Not properly formatted.");
            exit(EXIT_FAILURE);
        }

        printf("%s %2d, %4d", month(m), d, y);
    } else {
        fprintf(stderr, "Please provide one date argument to the program, formatted as mm-dd-yyyy or mm/dd/yyyy\n");
        exit(EXIT_FAILURE);
    }

    return 0;
}

What changed?

  • I changed the return type of month() . Its array is backed by string literals, so you shouldn't be able to accidentally modify them in future versions of your program, which would cause UB.
  • I introduced a range check in month() . It now returns a null pointer when when m is too small (eg 0/0/0 ) or too large (eg 25/09/2016 ), preventing some UB.
  • I removed all code regarding opening files. You don't want to open a file based on a file name in argv , you just want to use argv[1] as a string.
  • I introduced a check to see whether argv[1] exists. argc contains the size of argv , and if it's 2 , argv contains the program's name and its first command line argument.
  • Again, you don't want to read from a file, but parse a command line argument as a string, so I changed fscanf to sscanf .

Here we have a generic solution. The date can be passed via file (fscanf), via command line (sscanf) or typed (scanf).

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char* month(int m)
{
    char* months[] = { "January", "February", "March", "April", "May",
        "June", "July", "August", "September", "October",
        "November", "December" };
    return months[m - 1];
}

int main(int argc, char* argv[])
{
    int m = 0, d = 0, y = 0;

    FILE* fp;

    int wrongFormat = 0;

    if (argc > 1) 
    {
        if  ((fp = fopen(argv[1], "rb")) == NULL) 
        {
            if (sscanf(argv[1], "%d%*[/-]%d%*[/-]%d", &m, &d, &y) != 3) 
                wrongFormat = 1;
        }
        else 
        {
            if (fscanf(fp, "%d%*[/-]%d%*[/-]%d", &m, &d, &y) != 3)
                wrongFormat = 1;
        }
    }
    else 
    {
        printf("Type a date (mm-dd-yyyy) or (mm/dd/yyyy): \n");
        if (scanf("%d%*[/-]%d%*[/-]%d", &m, &d, &y) != 3)
            wrongFormat = 1;
    }

    if (wrongFormat) 
    {
        fprintf(stderr, "Not properly formatted.");
        exit(EXIT_FAILURE);
    }

    printf("%s %2d, %4d\n", month(m), d, y);

    return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM