C,使用argv []作为命令行参数

时间:2021-10-22 23:17:23

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.

我在使用这个程序时遇到了麻烦,当我使用stdin时它工作得很好但是当我修改它以从命令行获取字符时却没有。我知道我做错了什么但不知道什么,任何帮助都会非常感激。

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.

2 个解决方案

#1


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:

我修改了你的程序以解决你遇到的问题(并修复了一些未定义的行为,或简称为“UB”),但仅限于:

#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.
  • 我改变了月份的返回类型()。它的数组由字符串文字支持,因此您不应该在程序的未来版本中意外修改它们,这会导致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.
  • 我在月份()中引入了范围检查。当m太小(例如0/0/0)或太大(例如25/09/2016)时,它现在返回空指针,从而阻止了一些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.
  • 我删除了有关打开文件的所有代码。您不希望在argv中基于文件名打开文件,您只想将argv [1]用作字符串。
  • 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.
  • 我介绍了检查是否存在argv [1]。 argc包含argv的大小,如果是2,则argv包含程序的名称及其第一个命令行参数。
  • 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.
  • 同样,您不想从文件中读取,而是将命令行参数解析为字符串,因此我将fscanf更改为sscanf。

#2


0  

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

这里我们有一个通用的解决方案日期可以通过文件(fscanf),命令行(sscanf)或键入(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;
}

#1


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:

我修改了你的程序以解决你遇到的问题(并修复了一些未定义的行为,或简称为“UB”),但仅限于:

#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.
  • 我改变了月份的返回类型()。它的数组由字符串文字支持,因此您不应该在程序的未来版本中意外修改它们,这会导致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.
  • 我在月份()中引入了范围检查。当m太小(例如0/0/0)或太大(例如25/09/2016)时,它现在返回空指针,从而阻止了一些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.
  • 我删除了有关打开文件的所有代码。您不希望在argv中基于文件名打开文件,您只想将argv [1]用作字符串。
  • 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.
  • 我介绍了检查是否存在argv [1]。 argc包含argv的大小,如果是2,则argv包含程序的名称及其第一个命令行参数。
  • 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.
  • 同样,您不想从文件中读取,而是将命令行参数解析为字符串,因此我将fscanf更改为sscanf。

#2


0  

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

这里我们有一个通用的解决方案日期可以通过文件(fscanf),命令行(sscanf)或键入(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;
}