如何从文本文件中将数据读取为字符,然后将每个字符除以一个整数 [英] How to read data as characters from a text file and then divide each character by an int

查看:170
本文介绍了如何从文本文件中将数据读取为字符,然后将每个字符除以一个整数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图从文本文件中读取数据,然后将每个值除以3,然后再为每个新值打印输出值。

I am trying to read the data in from a text file, and then divide each value by 3, before printing the output value for each new value.

以下是文本文件格式的示例:

An example of the format of the text file can be seen below:

0.00707946 -0.0241935 23.9401 0 0.307334 0.2046

从上面的示例可以看出,每个值用空格隔开,有效数字的数量各不相同,数字可以是正数或负数。我可以成功读取并以字符的形式将值打印到cmd,但是,我的目标是将每个值除以数字3(整数),我正在努力做到这一点。

As can be seen from the above example, every value is seperated by a space, the number of significant figures vary, and numbers can be positive or negative. I can successfully read through and print out the values to cmd as characters, however, my aim is to divide every single value by the number 3 (an integer) which I am struggling to do.

我的问题是我在 printf 语句中选择的格式说明符的选择吗?或者选择显式强制转换为浮点数(我选择这样做是因为一些数字是浮点值)

Is my issue the choice of format specifier I have chosen in my printf statement? Or the choice of explicit casting to float (which I chose to do as some of the numbers are floating point values)

到目前为止我已经尝试过: / strong>

What I have tried so far:

   #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", &current_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(),请参见为什么gets()如此危险,永远不应该使用!。鉴于此,您尝试将每个字符除以 3 ,而不是每个浮点值。 atoi 是字符串的整数转换,而不是单个字符。

First, Never, never, Ever use gets(), see Why gets() is so dangerous it should never be used!. With that out of the way, you are attempting to divide each character by 3, not each floating-point value. atoi is an integer conversion for strings, not individual characters.

但是所有这些除了,您至少提供了一个真诚的尝试来解决。因此,让我们看一下如何改进。首先,不要在代码中使用 magic-numbers 25 magic-number ,如果您使用需要一个整数常量, #define 一个,例如

But all that aside, your at least provided a good-faith attempt at a solution. So let's look at how you can improve things. First, don't use magic-numbers, 25 in your code is a magic-number, instead if you need an integer constant, #define one, e.g.

#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 甚至都没有覆盖允许的文件名。

Also, Don't skimp on buffer size! On Linux the default PATH_MAX constant is 4096. 25 doesn't even begin to cover allowable filenames.

接下来,替换 gets fgets 。唯一的警告是,您现在必须修剪缓冲区中尾随的’\n’。您可以简单地使用 strcspn (它将报告不包含在 reject 字符串中的字符数)进行此操作。因此,选择 \r\n 的拒绝字符串可以满足您的要求,而 strcspn 返回的字符数到第一个。您只需 nul-terminate 在该索引处的字符串覆盖行尾,例如

Next, replace gets with fgets. The only caveat is that you now must trim the trailing '\n' from the buffer. You can do that simply with strcspn (which will report the number of characters that do not include those in the reject string). So choosing a reject string of "\r\n" covers you and strcspn returns the number of character up to the first of either. You simply nul-terminate your string at that index overwriting the line-ending, e.g.

    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 依次读取浮点数。 (除了%c %[...]以外的所有 scanf 转换丢弃前导空格)

Good job on validating your file was open for reading before using fp. Now you simply need to continue in a manner that will read floating-point numbers instead of characters. While I would generally recommend reading the remaining lines into a buffer and then calling sscanf to parse the values from it, you can also just use fscanf to read the floating-point numbers one-after-the-other. (all scanf conversions except "%c" and "%[...]" discard leading whitespace)

您可以非常简单地使用 fscanf 进行读取,然后除以 3 (这是我违反魔术数规则的地方),例如

You can very simply use fscanf to read, and then divide by 3 (which is where I violate the magic-number rule :), e.g.

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

就是这样。综上所述,您可以执行以下操作:

That's it. Putting it altogether, you could do:

#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;
}

示例用法/输出

$ ./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)了解使用哪些编译器选项

If the reason you have getchar() at the end of your code is to hold the terminal window open after your program finishes due to your using the Visual Studio IDE, you may want to consider just using the command line for small projects. (1) you don't have to set up a project in VS, (2) you can compile many different source files from the same directory in the time it takes to setup another project, and (3) you learn what compiler options you need, so you can then tell the IDE how you want your code compiled.

如果使用VS,它会提供 VS Developers Command Prompt,这只是 cmd.exe (命令提示符),并设置了适当的路径和编译器环境变量。 VS编译器是 cl.exe 。编译此代码所需要做的一切(在文件名 readdivfloats.c 中是:

If using VS, it provides the "VS Developers Command Prompt", which is just a cmd.exe (Command Prompt) with the appropriate path and compiler environment variables set. The VS compiler is cl.exe. All you need to do to compile this code (in filename readdivfloats.c is:

cl /nologo /W3 /wd4996 /Ox /Fereaddivfloats readdivfloats.c

The / Fe 选项只是命名生成的可执行文件,因此这里是同一目录中的 readdivfloats.exe 。保持源目录干净,因此我创建了 obj bin 子目录,以将所有目标文件和可执行文件放入其中。 / Fo 选项让您为目标文件命名(或者您可以简单地命名目录,而目标文件将以源文件的名称命名)。请注意,将目标文件放在 .\obj 子目录下,并将 exe 放在 .\bin 子目录,您将使用:

The /Fe option just names the resulting executable, so here it will be readdivfloats.exe in the same directory. I generally like to keep my source directory clean, so I create obj and bin subdirectories to put all the object files and executables in. The /Fo option let's you name the object file (or you can simply name a directory and the object files will be named with the name of the source file). So with that in mind, to put the object file below the .\obj subdirectory and the exe in the .\bin subdirectory, you would use:

cl /nologo /W3 /wd4996 /Ox /Foobj/ /Febin/readdivfloats readdivfloats.c

/ W3 转在出现完整警告时, / wd4996 禁用警告 4996 ,(烦人的 #define _CRT_SECURE_NO_WARNINGS 警告), Ox 打开快速优化。您只需在终端中输入 cl /?即可查看所有选项。

/W3 turns on full warnings, /wd4996 disables warning 4996, (the annoying #define _CRT_SECURE_NO_WARNINGS warning), Ox turns on fast optimization. You can see all options simply by entering cl /? in the terminal.

这篇关于如何从文本文件中将数据读取为字符,然后将每个字符除以一个整数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆