如何使用c++将ASCII文件的特定列存储(或转换)到数组中

how to store (or convert) a specific column of an ASCII file into an array using c++?

本文关键字:存储 转换 数组 c++ 何使用 ASCII 文件      更新时间:2023-10-16

我是C++新手。

我得到了一个包含3列143行的ASCII文件。第一列具有整数,而其余两列具有浮点值。

目标:将单独的三列存储到三个数组中,每个数组大小为143。

问题:使用cout打印时,最后一行重复,我不知道为什么。

ASCII文件示例:

2   41.3    25
2   46.2    30
2   51.5    40
2   56.7    45
3   49.5    525
3   46.2    450
3   54.0    575
3   59.5    650
5   36.0    500
5   39.0    525
5   31.8    480
5   36.4    520

我的代码:

void my_code()
 {
    FILE *pfile;
    int ball[150];
    float energy[150], channel[150];
    int ball1[150], i=0;
    float energy1[150], channel1[150];
    pfile = fopen("./ascii.txt","r");
    if (!pfile) continue;
    while(!feof(pfile))
    {
      fscanf(pfile,"%dt%ft%f",&ball[0],&energy[0],&channel[0]);
      ball1[i]=ball[0];
      energy1[i]=energy[0];
      channel1[i]=channel[0];      
      cout<<i<<"n";
      cout<<ball1[i]<<" "<<" "<<energy1[i]<<" "<<channel1[i]<<"n";
      i++;
     }
 }

请帮我理解。我也愿意为改进我的代码获得建议。

首先,不应编译代码,因为在循环外使用continue语句是无效的。

if (!pfile) continue;

所以我想知道为什么要编译你的代码。至于文件最后一行的值的重复,则是由于在循环的下一次迭代期间,下一行的读取以状态EOF完成,并且ball[0]、energy[0]和channel[0]的值没有改变。他们保持以前的价值观。

此外,如果只使用数组ball[0]、energy[0]和channel[0]中的第一个元素,那么声明它们也没有任何意义。

还不清楚为什么要混淆C++和C代码。事实上,该函数除了输出从文件中提取的值之外什么也不做。因此,定义数组没有任何意义。

我的代码也会这样做,看起来像

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
//...
void my_code()
{
    std::ifstream file( "./ascii.txt" );
    std::string line;
    while ( std::getline( file, line ) )
    {
        std::istringstream is( line );
        int v1;
        float v2, v3;
        if ( is >> v1 ) 
        {
            std::cout << v1;
            if ( is >> v2 ) 
            {
                std::cout << ' ' << v2;
                if ( is >> v3 )
                {
                    std::cout << ' ' << v3;
                }
            }
            std::cout << std::endl;
        }
    }
}             

如果你需要有arraya,那么代码可以看起来像

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
//...
void my_code()
{
    const size_t N = 143;
    int ball[N] = {};
    float energy[N] = {};
    float channel[N] = {};
    std::ifstream file( "./ascii.txt" );
    std::string line;
    size_t i = 0;    
    while ( i < N && std::getline( file, line ) )
    {
        std::istringstream is( line );
        if ( is >> ball[i] ) 
        {
            std::cout << ball[i];
            if ( is >> energy[i] ) 
            {
                std::cout << ' ' << energy[i];
                if ( is >> channel[i] )
                {
                    std::cout << ' ' << channel[i];
                }
            }
            std::cout << std::endl;
        }
    }
}             

您的问题在于循环测试在循环中的位置。试试这个:

while(true)
{
  fscanf(pfile,"%dt%ft%f",&ball[0],&energy[0],&channel[0]);
  if (feof(pfile)) break;
  ball1[i]=ball[0];
  energy1[i]=energy[0];
  channel1[i]=channel[0];      
  cout<<i<<"n";
  cout<<ball1[i]<<" "<<" "<<energy1[i]<<" "<<channel1[i]<<"n";
  i++;
}

编程新手经常犯这种错误。您的循环实际上非常适合早期尝试,但请准确地考虑循环想要退出的点。如果退出点关闭,则循环的最后一次迭代会产生奇怪的效果。

一旦你理解了答案,请注意,许多程序员过去都反对(有些人仍然反对(从循环操作中打断循环的风格。也就是说,一些程序员过去往往不喜欢break。就我个人而言,经过三十年的编程生涯,我通常不同意这种贬低,但如果你有一位不喜欢break的编程讲师,你自然应该考虑到讲师的偏好。

您可以检查fscanf的返回代码是否正确,如果出现错误,则退出循环

while (!feof(fp)) {
  ...
  ret = fscanf(pfile,"%dt%ft%f",&ball[0],&energy[0],&channel[0]);
  if (ferror(fp) || (ret == EOF)) {
    // handle the error
    break;
  } 
  ...
}