如何从文本文件中读取数据作为字符,然后将每个字符除以一个 int
How to read data as characters from a text file and then divide each character by an int
我正在尝试从文本文件中读取数据,然后将每个值除以 3,然后再打印每个新值的输出值。
文本文件的格式示例如下:
0.00707946 -0.0241935 23.9401 0 0.307334 0.2046
从上面的例子可以看出,每个值都用space隔开,有效数字的个数不同,数字可以是正数也可以是负数。我可以成功通读并将值打印为 cmd 作为 characters
,但是,我的目标是将每个值除以数字 3(integer
),我正在努力做到这一点。
我的问题是我在 printf
语句中选择的格式说明符的选择吗?或者选择显式转换为浮点数(我选择这样做是因为一些数字是浮点值)
到目前为止我尝试过的:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main()
{
char file_name[25];
int current_value = 0;
int new_value;
FILE *fp; //file handle
printf("Enter filename: \n");
gets(file_name);
fp = fopen(file_name, "r"); // read mode
//error handling
if (fp == NULL)
{
perror("Error while opening the file.\n");
getchar();
exit(EXIT_FAILURE);
}
while (fscanf(fp, "%d", ¤t_value) != EOF) //while end of file has not been detected
{
new_value = current_value / 3;
printf("%d ", new_value);
}
fclose(fp);
getchar();
return 0;
}
首先,从不,从不,从不使用 gets()
,参见 Why gets() is so dangerous it should never be used!。顺便说一下,您试图将每个字符除以 3
,而不是每个浮点值。 atoi
是字符串的 整数 转换,而不是单个字符。
但除此之外,您至少提供了一种善意的解决方案尝试。因此,让我们看看如何改进。首先,不要在你的代码中使用 magic-numbers,25
是一个 magic-number,而是如果你需要一个整数常量,#define
一个,例如
#define _CRT_SECURE_NO_WARNINGS //preprocessor requirement
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FNMAX 512 /* if you need a constant, define one (or more) */
int main (void) {
此外,不要吝啬缓冲区大小!在 Linux 上,默认的 PATH_MAX
常量是 4096
。 25
甚至没有开始涵盖允许的文件名。
接下来,将 gets
替换为 fgets
。唯一需要注意的是,您现在必须 trim 缓冲区中的尾随 '\n'
。您可以简单地使用 strcspn
来做到这一点(它将报告不包含在 reject 字符串中的字符数)。因此,选择 "\r\n"
的拒绝字符串涵盖您和 strcspn
returns 中的第一个字符数。您只需 nul-terminate 该索引处的字符串覆盖行尾,例如
printf ("Enter filename: ");
if (!fgets (file_name, FNMAX, stdin)) { /* validate EVERY input */
fputs ("(user canceled input)\n", stderr);
return 1;
}
file_name[strcspn(file_name, "\r\n")] = 0; /* trim '\n' from end */
在使用 fp
之前验证您的文件是否已打开以供阅读方面做得很好。现在您只需要以读取浮点数而不是字符的方式继续。虽然我通常建议将剩余的行读入缓冲区,然后调用 sscanf
来解析其中的值,但您也可以只使用 fscanf
逐个读取浮点数其他。 (所有 scanf
转换除了 "%c"
和 "%[...]"
丢弃前导空格)
你可以非常简单地使用 fscanf
来读取,然后除以 3
(这是我违反 magic-number 规则的地方 :)
,例如
/* read/print each floating-point value and value divided by 3 */
while (fscanf (fp, "%lf", &value) == 1)
printf ("\nvalue: %.4f\ndiv-3: %.4f\n", value, value / 3);
就是这样。总而言之,您可以这样做:
#define _CRT_SECURE_NO_WARNINGS //preprocessor requirement
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FNMAX 512 /* if you need a constant, define one (or more) */
int main (void) {
char file_name[FNMAX];
double value;
FILE *fp; //file handle
printf ("Enter filename: ");
if (!fgets (file_name, FNMAX, stdin)) { /* validate EVERY input */
fputs ("(user canceled input)\n", stderr);
return 1;
}
file_name[strcspn(file_name, "\r\n")] = 0; /* trim '\n' from end */
/* open/validate file open for reading */
if ((fp = fopen (file_name, "r")) == NULL) {
perror ("fopen-file");
return 1;
}
/* read/print each floating-point value and value divided by 3 */
while (fscanf (fp, "%lf", &value) == 1)
printf ("\nvalue: %.4f\ndiv-3: %.4f\n", value, value / 3);
fclose(fp); /* close file */
getchar(); /* hold terminal open on windows */
return 0;
}
示例Use/Output
$ ./bin/readdivfloats
Enter filename: dat/floats.txt
value: 0.0071
div-3: 0.0024
value: -0.0242
div-3: -0.0081
value: 23.9401
div-3: 7.9800
value: 0.0000
div-3: 0.0000
value: 0.3073
div-3: 0.1024
value: 0.2046
div-3: 0.0682
从命令行编译
如果你的代码末尾有 getchar()
的原因是由于你使用了 Visual Studio [=104=,所以在你的程序完成后保持终端 window 打开],你可能想考虑只对小项目使用命令行。 (1) 您不必在 VS 中设置项目,(2) 您可以在设置另一个项目所需的时间内从同一目录编译许多不同的源文件,以及 (3) 您了解您需要哪些编译器选项需要,这样您就可以告诉 IDE 您希望如何编译代码。
如果使用 VS,它会提供 "VS Developers Command Prompt",这只是一个 cmd.exe
(命令提示符),并设置了适当的路径和编译器环境变量。 VS编译器是cl.exe
。编译此代码(在文件名 readdivfloats.c
中,您需要做的是:
cl /nologo /W3 /wd4996 /Ox /Fereaddivfloats readdivfloats.c
/Fe
选项只是命名生成的可执行文件,所以这里它将是 readdivfloats.exe
在同一目录中。我一般喜欢保持我的源目录干净,所以我创建 obj
和 bin
子目录来放置所有目标文件和可执行文件。 /Fo
选项让你命名目标文件(或您可以简单地命名一个目录,目标文件将以源文件的名称命名)。因此,考虑到这一点,要将目标文件放在 .\obj
子目录下,将 exe
放在 .\bin
子目录下,您可以使用:
cl /nologo /W3 /wd4996 /Ox /Foobj/ /Febin/readdivfloats readdivfloats.c
/W3
开启完整警告,/wd4996
关闭警告4996
,(烦人的#define _CRT_SECURE_NO_WARNINGS
警告),Ox
开启快速优化。您只需在终端中输入 cl /?
即可查看所有选项。
我正在尝试从文本文件中读取数据,然后将每个值除以 3,然后再打印每个新值的输出值。
文本文件的格式示例如下:
0.00707946 -0.0241935 23.9401 0 0.307334 0.2046
从上面的例子可以看出,每个值都用space隔开,有效数字的个数不同,数字可以是正数也可以是负数。我可以成功通读并将值打印为 cmd 作为 characters
,但是,我的目标是将每个值除以数字 3(integer
),我正在努力做到这一点。
我的问题是我在 printf
语句中选择的格式说明符的选择吗?或者选择显式转换为浮点数(我选择这样做是因为一些数字是浮点值)
到目前为止我尝试过的:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main()
{
char file_name[25];
int current_value = 0;
int new_value;
FILE *fp; //file handle
printf("Enter filename: \n");
gets(file_name);
fp = fopen(file_name, "r"); // read mode
//error handling
if (fp == NULL)
{
perror("Error while opening the file.\n");
getchar();
exit(EXIT_FAILURE);
}
while (fscanf(fp, "%d", ¤t_value) != EOF) //while end of file has not been detected
{
new_value = current_value / 3;
printf("%d ", new_value);
}
fclose(fp);
getchar();
return 0;
}
首先,从不,从不,从不使用 gets()
,参见 Why gets() is so dangerous it should never be used!。顺便说一下,您试图将每个字符除以 3
,而不是每个浮点值。 atoi
是字符串的 整数 转换,而不是单个字符。
但除此之外,您至少提供了一种善意的解决方案尝试。因此,让我们看看如何改进。首先,不要在你的代码中使用 magic-numbers,25
是一个 magic-number,而是如果你需要一个整数常量,#define
一个,例如
#define _CRT_SECURE_NO_WARNINGS //preprocessor requirement
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FNMAX 512 /* if you need a constant, define one (or more) */
int main (void) {
此外,不要吝啬缓冲区大小!在 Linux 上,默认的 PATH_MAX
常量是 4096
。 25
甚至没有开始涵盖允许的文件名。
接下来,将 gets
替换为 fgets
。唯一需要注意的是,您现在必须 trim 缓冲区中的尾随 '\n'
。您可以简单地使用 strcspn
来做到这一点(它将报告不包含在 reject 字符串中的字符数)。因此,选择 "\r\n"
的拒绝字符串涵盖您和 strcspn
returns 中的第一个字符数。您只需 nul-terminate 该索引处的字符串覆盖行尾,例如
printf ("Enter filename: ");
if (!fgets (file_name, FNMAX, stdin)) { /* validate EVERY input */
fputs ("(user canceled input)\n", stderr);
return 1;
}
file_name[strcspn(file_name, "\r\n")] = 0; /* trim '\n' from end */
在使用 fp
之前验证您的文件是否已打开以供阅读方面做得很好。现在您只需要以读取浮点数而不是字符的方式继续。虽然我通常建议将剩余的行读入缓冲区,然后调用 sscanf
来解析其中的值,但您也可以只使用 fscanf
逐个读取浮点数其他。 (所有 scanf
转换除了 "%c"
和 "%[...]"
丢弃前导空格)
你可以非常简单地使用 fscanf
来读取,然后除以 3
(这是我违反 magic-number 规则的地方 :)
,例如
/* read/print each floating-point value and value divided by 3 */
while (fscanf (fp, "%lf", &value) == 1)
printf ("\nvalue: %.4f\ndiv-3: %.4f\n", value, value / 3);
就是这样。总而言之,您可以这样做:
#define _CRT_SECURE_NO_WARNINGS //preprocessor requirement
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FNMAX 512 /* if you need a constant, define one (or more) */
int main (void) {
char file_name[FNMAX];
double value;
FILE *fp; //file handle
printf ("Enter filename: ");
if (!fgets (file_name, FNMAX, stdin)) { /* validate EVERY input */
fputs ("(user canceled input)\n", stderr);
return 1;
}
file_name[strcspn(file_name, "\r\n")] = 0; /* trim '\n' from end */
/* open/validate file open for reading */
if ((fp = fopen (file_name, "r")) == NULL) {
perror ("fopen-file");
return 1;
}
/* read/print each floating-point value and value divided by 3 */
while (fscanf (fp, "%lf", &value) == 1)
printf ("\nvalue: %.4f\ndiv-3: %.4f\n", value, value / 3);
fclose(fp); /* close file */
getchar(); /* hold terminal open on windows */
return 0;
}
示例Use/Output
$ ./bin/readdivfloats
Enter filename: dat/floats.txt
value: 0.0071
div-3: 0.0024
value: -0.0242
div-3: -0.0081
value: 23.9401
div-3: 7.9800
value: 0.0000
div-3: 0.0000
value: 0.3073
div-3: 0.1024
value: 0.2046
div-3: 0.0682
从命令行编译
如果你的代码末尾有 getchar()
的原因是由于你使用了 Visual Studio [=104=,所以在你的程序完成后保持终端 window 打开],你可能想考虑只对小项目使用命令行。 (1) 您不必在 VS 中设置项目,(2) 您可以在设置另一个项目所需的时间内从同一目录编译许多不同的源文件,以及 (3) 您了解您需要哪些编译器选项需要,这样您就可以告诉 IDE 您希望如何编译代码。
如果使用 VS,它会提供 "VS Developers Command Prompt",这只是一个 cmd.exe
(命令提示符),并设置了适当的路径和编译器环境变量。 VS编译器是cl.exe
。编译此代码(在文件名 readdivfloats.c
中,您需要做的是:
cl /nologo /W3 /wd4996 /Ox /Fereaddivfloats readdivfloats.c
/Fe
选项只是命名生成的可执行文件,所以这里它将是 readdivfloats.exe
在同一目录中。我一般喜欢保持我的源目录干净,所以我创建 obj
和 bin
子目录来放置所有目标文件和可执行文件。 /Fo
选项让你命名目标文件(或您可以简单地命名一个目录,目标文件将以源文件的名称命名)。因此,考虑到这一点,要将目标文件放在 .\obj
子目录下,将 exe
放在 .\bin
子目录下,您可以使用:
cl /nologo /W3 /wd4996 /Ox /Foobj/ /Febin/readdivfloats readdivfloats.c
/W3
开启完整警告,/wd4996
关闭警告4996
,(烦人的#define _CRT_SECURE_NO_WARNINGS
警告),Ox
开启快速优化。您只需在终端中输入 cl /?
即可查看所有选项。