我正在尝试从文本文件中读取数据,然后将每个值除以3,然后在打印每个新值的输出值之前。
文本文件格式的一个示例如下:
0.00707946 -0.0241935 23.9401 0 0.307334 0.2046
可以从上面的示例中可以看出,每个值都被一个空间分开,重要数字的数量变化,而且数字可以为正或负数。我可以成功地阅读并将其打印为CMD为characters
,但是,我的目的是将每个值除以数字3(a 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()
,请参阅为什么get get((如此危险,它永远不应使用!因此,您正在尝试将每个字符除以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
甚至没有开始涵盖允许的文件名。
接下来,用fgets
替换gets
。唯一的警告是,您现在必须从缓冲区中修剪尾随的'n'
。您只需使用strcspn
即可完成此操作(这将报告不包含 recood 字符串中的字符数(。因此,选择"rn"
的拒绝字符串覆盖您,strcspn
将字符数返回到两个的第一个。您只需在该索引覆盖线路终止的字符串,例如
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, "rn")] = 0; /* trim 'n' from end */
在使用fp
之前,在验证文件方面的良好工作是可以打开的。现在,您只需要以读取浮点数而不是字符的方式继续。虽然我通常建议将剩余的线读取到缓冲区中,然后致电sscanf
从中解析值,但您也可以使用fscanf
读取浮点数数字。(除了"%c"
和"%[...]"
丢弃领先的whitespace外,所有scanf
转换(
您可以非常简单地使用fscanf
来读取,然后除以3
(这是我违反 magic-number 规则:)
,例如,例如
/* read/print each floating-point value and value divided by 3 */
while (fscanf (fp, "%lf", &value) == 1)
printf ("nvalue: %.4fndiv-3: %.4fn", 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, "rn")] = 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: %.4fndiv-3: %.4fn", value, value / 3);
fclose(fp); /* close file */
getchar(); /* hold terminal open on windows */
return 0;
}
示例使用/输出
$ ./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 IDE而在程序完成后打开终端窗口,则可能需要考虑仅将命令行用于小型项目。(1(您无需在VS中设置一个项目,(2(您可以在设置另一个项目的时间内从同一目录中编译许多不同的源文件,并且(3(您了解哪些编译器选项需要,因此您可以告诉IDE如何编译代码。
如果使用VS,它提供了" VS Developers命令提示符",它只是一个带有适当路径和编译器环境变量设置的cmd.exe
(命令提示符(。VS编译器是cl.exe
。您需要要做的一切来编译此代码(在文件名中readdivfloats.c
是:
cl /nologo /W3 /wd4996 /Ox /Fereaddivfloats readdivfloats.c
/Fe
选项仅命名由此产生的可执行文件,因此在同一目录中将是readdivfloats.exe
。我通常喜欢保持我的源目录清洁,因此我创建obj
和bin
子目录以将所有对象文件和可执行文件放入中。/Fo
选项让您命名对象文件(或者您可以简单地命名目录,而对象文件将为目录命名为源文件的名称(。因此,考虑到这一点,要将对象文件放在.obj
子目录下方和.bin
子目录中的exe
下方,您将使用:
cl /nologo /W3 /wd4996 /Ox /Foobj/ /Febin/readdivfloats readdivfloats.c
/W3
打开完整警告,/wd4996
禁用警告4996
,(烦人的#define _CRT_SECURE_NO_WARNINGS
警告(,Ox
打开快速优化。您只需在终端中输入cl /?
即可看到所有选项。