преобразовать значения в строку в массив с плавающей точкой - PullRequest
1 голос
/ 07 декабря 2009

У меня есть строка в C, которую я получил из какого-то алгоритма. он имеет числовые значения в таком формате

0.100
0.840
0.030
0.460
0.760
-0.090

и т. Д.

необходимо хранить каждое из этих числовых значений в массиве с плавающей запятой для числовой обработки. я новичок в C и нашел обработку строк в C, чтобы быть сложным. Может кто-нибудь сказать мне, как я мог бы реализовать это.

Ответы [ 6 ]

2 голосов
/ 07 декабря 2009

Использование strtod(). В отличие от atof() он может обнаруживать ошибки во входной строке.

#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() возвращает прочитанное значение, если не было ошибки.

если err указывает на переданную строку, из этой строки ничего нельзя использовать, , поэтому в моем фрагменте выше я увеличиваю p, чтобы продолжить чтение со следующей позиции.

если err равен NULL или указывает на пустую строку, ошибки не было, поэтому в моем фрагменте я печатаю значение и останавливаю цикл.

если err указывает где-то в строке (не сам p, проверенный ранее), то есть символ с ошибкой, в моем фрагменте выше, я знаю, что что-то прочитано, поэтому я его печатаю, устанавливаю p один за ошибкой и цикл.


Редактировать Для полноты картины я должен упомянуть еще случай ошибки. Может случиться, что strtod() читает последовательность символов, которые (хотя и допустимые) не могут быть представлены double. В этом случае errno устанавливается на ERANGE, а само значение является «бессмысленным». Вы должны установить errno в 0 перед вызовом strtod() и проверить его позже, прежде чем использовать возвращаемое значение. Для очень малых входных значений (например, «1E-42000») настройка errno определяется реализацией, но возвращается 0 (или почти 0).

1 голос
/ 07 декабря 2009

Все ли значения в одной строке, например, «0,100 0,840 0,030 ...», или у вас есть несколько отдельных строк, например «0,100», «0,840», «0,030» и т. Д.? Если они находятся в одной строке, разделены ли они пробелами (табуляцией, пробелами, символами новой строки) или печатными символами (запятая, точка с запятой)? Знаете ли вы, сколько значений у вас есть заранее (то есть, насколько большим должен быть ваш массив float)?

Чтобы преобразовать строку, представляющую одно значение с плавающей запятой, в double, используйте strtod() следующим образом:

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
   */
}

Подробнее см. strtod(). unconverted будет указывать на первый символ в строке, который не был преобразован strtod(); если это не пробел или 0, то ваша строка неправильно отформатирована для значения с плавающей запятой и должна быть отклонена.

Если все значения находятся в одной строке, вам придется разбить строку на отдельные токены. Самый простой (хотя и небезопасный) способ сделать это - использовать 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
     */
  }
}

Подробнее см. На strtok().

Если вы не знаете, сколько значений у вас заранее, вам нужно будет немного поработать с памятью. Вы можете динамически выделить массив с плавающей точкой некоторого начального размера, используя malloc() или realloc(), а затем периодически расширять его, используя 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;
  }
}

Не забудьте free() массив, когда вы закончите с ним.

0 голосов
/ 07 декабря 2009

Если это одна строка, сначала вам нужно разбить ее на символ новой строки (s?), А затем вы можете использовать функцию "atof" stdlib для создания из них плавающих чисел. как то так:

0 голосов
/ 07 декабря 2009

предполагается, что ваша строка

char *str;

используйте что-то вроде:

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';
}
0 голосов
/ 07 декабря 2009

Нужная функция называется 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;
}
0 голосов
/ 07 декабря 2009
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...