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 whenm
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 useargv[1]
as a string. - 我删除了有关打开文件的所有代码。您不希望在argv中基于文件名打开文件,您只想将argv [1]用作字符串。
- I introduced a check to see whether
argv[1]
exists.argc
contains the size ofargv
, and if it's2
,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
tosscanf
. - 同样,您不想从文件中读取,而是将命令行参数解析为字符串,因此我将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 whenm
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 useargv[1]
as a string. - 我删除了有关打开文件的所有代码。您不希望在argv中基于文件名打开文件,您只想将argv [1]用作字符串。
- I introduced a check to see whether
argv[1]
exists.argc
contains the size ofargv
, and if it's2
,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
tosscanf
. - 同样,您不想从文件中读取,而是将命令行参数解析为字符串,因此我将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;
}