1

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.
8
  • 1
    Im using codeblocks ide, I typed 01/30/1990 in the Program argument windows, I also have used gcc to run it and it says "The system cannot accept the date you entered". "A required priviledge is not held by the client". Commented Sep 25, 2016 at 0:25
  • 2
    fopen("01/30/1999","rb") will try to open a file with the path 01/30/1999. Obviously, no such file exists. Commented Sep 25, 2016 at 0:27
  • 2
    argv[1] has undefined behaviour unless you previously ascertain that argc is at least two. Commented Sep 25, 2016 at 0:27
  • 1
    Don't use fscanf (file-scanf) on fp, but use sscanf (string-scanf) on argv[1]. Commented Sep 25, 2016 at 0:54
  • 2
    Instead of fprintf(stderr,"Couldn't open the file. "); (which produces a nearly useless error message), try perror( argv[1]), which will tell you exactly what the problem is. Commented Sep 25, 2016 at 1:26

2 Answers 2

2

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 (e.g. 0/0/0) or too large (e.g. 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.
Sign up to request clarification or add additional context in comments.

Comments

0

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;
}

4 Comments

OP's comment shows that this isn't what they wanted: "How can I get the input from the command line and then extract the information to put them into variables?"
m, d and y are variables.
That's not the point. OP wants to read the input from the command line, instead of from a file specified on the command line.
OK, @Rhymoid. Now it will work with command line as well. Thanks for your comment and +1 for your answer that is also correct!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.