【问题标题】:C, using argv[] for command line argumentsC,使用 argv[] 作为命令行参数
【发布时间】:2016-09-26 04:57:13
【问题描述】:

我在使用这个程序时遇到了问题,当我使用标准输入时它运行良好,但当我修改它以从命令行获取字符时它没有。我知道我做错了什么,但不知道是什么,任何帮助将不胜感激。

描述和代码:

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

输入:

01/30/1990

输出:

Couldn't open the file.

【问题讨论】:

  • 我正在使用代码块 ide,我在程序参数窗口中输入了 01/30/1990,我还使用 gcc 运行它,它显示“系统无法接受您输入的日期”。 “客户不拥有所需的特权”。
  • fopen("01/30/1999","rb") 将尝试打开路径为01/30/1999 的文件。显然,不存在这样的文件。
  • argv[1] 具有未定义的行为,除非您之前确定 argc 至少为两个。
  • 不要在fp上使用fscanf (file-scanf),而是在argv[1]上使用sscanf (string-scanf)。
  • 不要使用fprintf(stderr,"Couldn't open the file. ");(它会产生几乎无用的错误消息),试试perror( argv[1]),它会告诉你问题出在哪里。

标签: c file argv


【解决方案1】:

我修改了您的程序以解决您遇到的问题(并修复一些未定义的行为,或简称为“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;
}

发生了什么变化?

  • 我更改了month() 的返回类型。它的数组由字符串字面量支持,因此您不应在将来的程序版本中意外修改它们,否则会导致 UB。
  • 我在month() 中引入了范围检查。现在,当m 太小(例如0/0/0)或太大(例如25/09/2016)时,它会返回一个空指针,从而阻止一些UB。
  • 我删除了所有有关打开文件的代码。您不想根据argv 中的文件名打开文件,只想将argv[1] 用作字符串。
  • 我引入了检查argv[1] 是否存在。 argc 包含argv 的大小,如果是2argv 包含程序的名称和它的第一个命令行参数。
  • 同样,您不想从文件中读取,而是将命令行参数解析为字符串,因此我将 fscanf 更改为 sscanf

【讨论】:

    【解决方案2】:

    这里我们有一个通用的解决方案。日期可以通过文件 (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;
    }
    

    【讨论】:

    • OP 的评论表明这不是他们想要的:“如何从命令行获取输入,然后提取信息以将它们放入变量中?”
    • m、d 和 y 是变量。
    • 这不是重点。 OP 希望从命令行读取输入,而不是从命令行上指定的文件读取。
    • 好的,@Rhymoid。现在它也可以与命令行一起使用。感谢您的评论和 +1 您的回答也是正确的!
    猜你喜欢
    • 1970-01-01
    • 2020-01-23
    • 2013-06-13
    • 2020-11-15
    • 2018-01-07
    • 1970-01-01
    • 2015-04-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多