views:

345

answers:

6

i have a string in C which i got from some algorithm. it has numeric values in a format like this

0.100
0.840
0.030
0.460
0.760
-0.090

and so on

in need to store each of these numeric values into a float array for numeric processing. i am new to C and found string handling in C to be complex. can anyone tell me how i might implement this.

A: 

The function you want is called fscanf.

/* fscanf example */
/* Stolen from cplusplus.com
   Modified by C Ross */
#include <stdio.h>

int main ()
{
  char str [80];
  float f;
  FILE * pFile;

  pFile = fopen ("myfile.txt","r");
  /* Loop over this and add to an array, linked list, whatever */
  fscanf (pFile, "%f", &f);
  fclose (pFile);
  printf ("I have read: %f \n",f);
  return 0;
}
C. Ross
A: 

supposed your string is

char *str;

use something like:

double d[<enter array size here>];
double *pd = d;

for(char *p = str; p = strchr(p, '\n'); p++, pd++)
{
    *p = 0;
    *pd = atof(p);
    *p = '\n';
}
RED SOFT ADAIR
A: 

If it is one string, first you need to split it on the new line character(s?) and then you can use the "atof" stdlib function to create floating numbers from them. something like this:

progician
+2  A: 

Use strtod(). Unlike atof() it can detect errors in the input string.

#include <stdio.h>
#include <stdlib.h>

int main(void) {
  char buf[] = "0.100\n0.8foo40\n0.030\n\n\n\n0.460\n0.760bar\n-0.090trash";
  char *err, *p = buf;
  double val;
  while (*p) {
    val = strtod(p, &err);
    if (p == err) p++;
    else if ((err == NULL) || (*err == 0)) { printf("Value: %f\n", val); break; }
    else { printf("Value: %f\n", val); p = err + 1; }
  }
  return 0;
}

strtod() returns the value read unless there was an error.

if err points to the string passed in, nothing could be used from the string, so in my snippet above, I increment p to continue reading from the next position.

if err is NULL or points to an empty string, there was no error, so, in my snippet, I print the value and stop the loop.

if err points somewhere in the string (not p itself, tested before), that is the character with error, in my snippet above, I know something was read, so I print it, set p one past the error and loop.


Edit For completeness sake, I should mention yet the case of error. It might happen that strtod() reads a sequence of characters that (although valid) cannot be represented by a double. In that case, errno is set to ERANGE and the value itself is "meaningless". You should set errno to 0 before calling strtod() and check it afterwards, before using the returned value. For extremely small input values (eg "1E-42000") setting errno is implementation defined, but 0 (or almost 0) is returned.

pmg
A: 

Are all the values in a single string, like "0.100 0.840 0.030 ...", or do you have a bunch of separate strings, like "0.100", "0.840", "0.030", etc.? If they're in a single string, are they separated by whitespace (tabs, spaces, newlines) or by printing characters (comma, semicolon)? Do you know how many values you have ahead of time (i.e., how big your float array needs to be)?

To convert a string representing a single floating point value to double, use strtod() as follows:

char valueText[] = "123.45";
char *unconverted;
double value;

value = strtod(valueText, &unconverted);
if (!isspace(*unconverted) && *unconverted!= 0)
{
  /**
   * Input string contains a character that's not valid
   * in a floating point constant
   */
}

Read up on strtod() for details. unconverted will point to the first character in the string that wasn't converted by strtod(); if it isn't whitespace or 0, then your string isn't properly formatted for a floating point value and should be rejected.

If all the values are in a single string, you're going to have to break the string into distinct tokens. The easy (if somewhat unsafe) way to do this is to use strtok():

char input[] = "1.2 2.3 3.4 4.5 5.6 6.7 7.8";
char *delim = " "; // input separated by spaces
char *token = NULL;

for (token = strtok(input, delim); token != NULL; token = strtok(NULL, delim))
{
  char *unconverted;
  double value = strtod(token, &unconverted);
  if (!isspace(*unconverted) && *unconverted != 0)
  {
    /**
     * Input string contains a character that's not valid
     * in a floating point constant
     */
  }
}

Read up on strtok() for details.

If you don't know how many values you have up front, you'll need to do some memory management. You can dynamically allocate an array of float of some initial size using malloc() or realloc(), and then extend it periodically using realloc():

#define INITIAL_EXTENT 10

double *array = NULL;
size_t arraySize = 0;
size_t arrayIdx = 0;

char input[] = ...; // some long input string
char *delim = ...; // whatever the delimiter set is
char *token;

/**
 * Create the float array at some initial size
 */
array = malloc(sizeof *array * INITIAL_EXTENT));
if (array)
{
  arraySize = INITIAL_EXTENT;
}
/**
 * Loop through your input string
 */
for (token = strtok(input, delim); token != NULL; token = strtok(NULL, delim))
{
  double val;
  char *unconverted;
  if (arrayIdx == arraySize)
  {
    /**
     * We've reached the end of the array, so we need to extend it.  
     * A popular approach is to double the array size instead of
     * using a fixed extent; that way we minimize the number
     * of calls to realloc(), which is relatively expensive.  
     *
     * Use a temporary variable to receive the result; that way,
     * if the realloc operation fails, we don't lose our
     * original pointer.
     */
    double *tmp = realloc(array, sizeof *array * (arraySize * 2));
    if (tmp != NULL)
    {
      array = tmp;
      arraySize *= 2;
    }
    else
    {
      /**
       * Memory allocation failed; for this example, we just exit the loop
       */
      fprintf(stderr, "Memory allocation failed; exiting loop\n");
      break;
    }
  }
  /**
   * Convert the next token to a float value
   */
  val = strtod(token, &unconverted);
  if (!isspace(*unconverted) && *unconverted != 0)
  {
    /**
     * Bad input string.  Again, we just bail.
     */
    fprintf(stderr, "\"%s\" is not a valid floating-point number\n", token);
    break;
  }
  else
  {
    array[arrayIdx++] = val;
  }
}

Don't forget to free() array when you're done with it.

John Bode
i tried implementing this but i get a segmentation fault error every time. looking into it. do u have any idea what might have caused it?
sfactor
Where does the segfault occur? On reading the token? Converting the token? Extending the array? Assigning the value? I tossed that code off the top of my head so I wouldn't be surprised if there were mistakes, but it would help to know exactly where it's dying. If you can run it through a debugger to find the exact line, that would be helpful.
John Bode