1

I would like to push the below data into a vector using the below code.But my code works only for integers.How can I do this for the below data? Thank you.

My data:

    M,0.455,0.365,0.095,0.514,0.2245,0.101,0.15,15
    M,0.35,0.265,0.09,0.2255,0.0995,0.0485,0.07,7
    F,0.53,0.42,0.135,0.677,0.2565,0.1415,0.21,9
    M,0.44,0.365,0.125,0.516,0.2155,0.114,0.155,10
    I,0.33,0.255,0.08,0.205,0.0895,0.0395,0.055,7
    I,0.425,0.3,0.095,0.3515,0.141,0.0775,0.12,8
    F,0.53,0.415,0.15,0.7775,0.237,0.1415,0.33,20
    F,0.545,0.425,0.125,0.768,0.294,0.1495,0.26,16
    M,0.475,0.37,0.125,0.5095,0.2165,0.1125,0.165,9
    F,0.55,0.44,0.15,0.8945,0.3145,0.151,0.32,19

My code:

      fp = fopen(argv[1], "r"); //Opening the input file in read mode.
      if(!fp)
      {
          printf("open data source file failed!\n");
          goto MAINEXIT;
      }

      int ivalue;
      //extract data from files
      while(fscanf(fp,"%d,",&ivalue)!=EOF)
      {
          printf("Counter-%d\n",counter++);
          srcdata.push_back(ivalue); //Pushing value by value into the vector with "," delimiter.
      }

      if(fp)
      fclose(fp);
imreal
  • 10,178
  • 2
  • 32
  • 48
Teja
  • 13,214
  • 36
  • 93
  • 155
  • Where is `srcdata` initialised, is it std::vector? – Fantastic Mr Fox Dec 05 '12 at 02:18
  • But I have string data too in the 1st column.. How do I handle that? – Teja Dec 05 '12 at 02:21
  • @SOaddict, are you using C or C++, exactly? For C++, you can refer to [Splitting a string in C++](http://stackoverflow.com/questions/236129/splitting-a-string-in-c) – Dante May Code Dec 05 '12 at 02:29
  • My code is a club of C and C++. – Teja Dec 05 '12 at 02:32
  • 1
    "A club of C and C++"? You'd be better off picking one or the other instead of trying to mix the two. Since you're using an STL vector, you *really* should use C++ `iostream` instead of C `stdio` routines. – John Bode Dec 05 '12 at 02:36
  • But already my code is built and cant change it into C++.I am using C++ vectors and using C file functions.... – Teja Dec 05 '12 at 02:55

2 Answers2

2

%d is for integers. Change it to %lf for double, and change other parts accordingly, for example, change ivalue to double.


According to your comment in the question, I think you might need something like

while(fscanf(fp,"%s", str)!=EOF)
{
    char* pch = strtok(str, ",");
    pch = strtok(NULL, ","); // skip first
    while (pch != NULL)
    {
        double d = atof(pch);
        printf("Counter-%d\n",counter++);
        srcdata.push_back(d);
        pch = strtok (NULL, ",");
    }
}
Dante May Code
  • 11,177
  • 9
  • 49
  • 81
0

Since you're using a C++ STL container (vector), you really should be using C++ I/O (iostream) instead of C I/O (stdio). It's safer, more flexible, and can wind up saving you some heartburn.

Here's a quick-n-dirty sample showing how you can read that data into a vector:

#include <iostream>
#include <iomanip>
#include <vector>
#include <iterator>
#include <sstream>
#include <string>

/**
 * Create a struct type to represent each record,
 * with one char member (which I'm calling "gender"
 * based on the 'M' and 'F', but that's just a guess),
 * 7 doubles (which I've gathered into a fixed-size
 * array), and one integer.
 *
 * I've also overloaded the stream << and >> operators
 * to read and write the struct as a single entity.
 */
struct record {
  char gender;
  double dvar[7];
  int ivar;

  record() { }
  virtual ~record() { }

  std::ostream& operator<<(std::ostream& s)
  {
    s << gender << " ";
    for (int i = 0; i < 7; i++)
      s << std::fixed << std::setw(8) << std::setprecision(4) << dvar[i] << " ";
    s << std::setw(3) << ivar;
    return s;
  }

  std::istream& operator>>(std::istream& s)
  {
    char delim;
    s >> gender >> delim;
    for (int i = 0; i < 7; i++)
      s >> dvar[i] >> delim;
    s >> ivar;
    return s;
  }
};

/**
 * Overload the << and >> operators outside of the struct
 * definition; this is necessary for the istream and ostream
 * iterators to function properly.  Each operator simply
 * calls the overloaded operator in the struct definition
 */
std::ostream& operator<<(std::ostream& s, const record& r)
{
  const_cast<record&>(r).operator<<(s);
  return s;
}

std::istream& operator>>(std::istream& s, record& r)
{
  r.operator>>(s);
  return s;
}

/**
 * For the purpose of this example I'm reading from a string
 * stream local to main; however, you can swap out the string
 * stream with a C++ file stream (ifstream) and use it in the
 * copy method *exactly* as you use the string stream:
 *
 *    std::ifstream infile(filename);
 *    ...
 *    std::copy(std::istream_iterator<record>(infile),
 *              std::istream_iterator<record>(),
 *              std::back_inserter(myRec));
 */
int main(void)
{
  std::vector<record> myRec;

  /**
   * We're using a local string and string stream for the purpose of
   * this example, but the handling of a string stream and a file
   * stream would be exactly the same.
   */
  std::string data = "M,0.455,0.365,0.095,0.514,0.2245,0.101,0.15,15"
                   "M,0.35,0.265,0.09,0.2255,0.0995,0.0485,0.07,7"
                   "F,0.53,0.42,0.135,0.677,0.2565,0.1415,0.21,9"
                   "M,0.44,0.365,0.125,0.516,0.2155,0.114,0.155,10"
                   "I,0.33,0.255,0.08,0.205,0.0895,0.0395,0.055,7"
                   "I,0.425,0.3,0.095,0.3515,0.141,0.0775,0.12,8"
                   "F,0.53,0.415,0.15,0.7775,0.237,0.1415,0.33,20"
                   "F,0.545,0.425,0.125,0.768,0.294,0.1495,0.26,16"
                   "M,0.475,0.37,0.125,0.5095,0.2165,0.1125,0.165,9"
                   "F,0.55,0.44,0.15,0.8945,0.3145,0.151,0.32,19";

  std::stringstream dataStream;
  /**
   * Write the contents of the string to the string stream
   */
  dataStream << data;
  /**
   * Read the contents of the string stream into the vector
   */
  std::copy(std::istream_iterator<record>(dataStream),
            std::istream_iterator<record>(),
            std::back_inserter(myRec));

  std::cout << "Read " << myRec.size() << " records" << std::endl;

  /**
   * Write the contents of the vector to standard output.
   */
  std::copy(myRec.begin(), 
            myRec.end(), 
            std::ostream_iterator<record>(std::cout, "\n"));

  return 0;
}

This is pretty simplistic; there's no sort of error handling or way to deal with malformed input. However, I think it's a pretty good illustration of the power of C++ I/O routines.

However, if you're stuck on C I/O, you could do something like the following:

struct record {
  char gender;
  double dvar[7];
  int ivar;
};

int getRecord(FILE *stream, struct record *r)
{
  char line[80]; // assuming each line is less than 80 characters long

  if (fgets(line, sizeof line, stream))
  {
    int count = sscanf(line, "%c,%f,%f,%f,%f,%f,%f,%f,%d",
                  &r->gender,
                  &r->dvar[0],
                  &r->dvar[1],
                  &r->dvar[2],
                  &r->dvar[3],
                  &r->dvar[4],
                  &r->dvar[5],
                  &r->dvar[6],
                  &r->ivar);
    if (count < 8)
    {
      fprintf(stderr, "Input line \"%s\" is malformed\n", line);
      return 0;
    }
  }
  else
  {
    if (feof(stream))
    {
      fprintf(stderr, "Reached end of file\n");
    }
    else
    {
      perror("Error on read");
    }
    return 0;
  }
  return 1;
}

int main(void)
{
   std::vector<record> myRec;
   FILE *input = fopen("myfile.dat", "r");
   record r;

   while(getRecord(input, &r))
     myRec.push_back(r);
   ...
}    

I strongly recommend using the C++ I/O routines for this; mixing C I/O with C++ is a recipe for heartburn.

John Bode
  • 119,563
  • 19
  • 122
  • 198