3

I have a flat file with the ff data:

date;quantity;price;item

I want create a data record using the following struct:

typedef struct {
  char * date, * item;
  int quantity;
  float price, total;
} expense_record;

I created the following initializing method:

expense_record initialize(char * date, int quantity, char *price, char *item) {
  expense_record e;
  e.date = date;
  e.quantity = quantity;
  e.item = item;
  /* set price */
  return e;
}

My question is how to set the price as float (as required by the struct) from the char *price. The closest I got, i.e. without generating a compiler error was

 e.price = *(float *)price

but this results in segmentation faults.

Thanks!

DannyClay
  • 260
  • 3
  • 11
  • What do you pass to `initialize` as parameter `price`? – us2012 Sep 09 '13 at 13:26
  • So you have a price in human readable format, and would like to convert it to a float? In that case, you have to parse it, as in [this question](http://stackoverflow.com/questions/7951019/convert-string-to-float) ... Type casting is not for this purpose... – ppeterka Sep 09 '13 at 13:28
  • what do you do with `quantity`? – Rohan Sep 09 '13 at 13:28
  • @us2012 @ppeterka66 Yes, I have a `price` in human readable format, e.g. 10.50 which is passed to the `initialize` method as `char * price`. – DannyClay Sep 09 '13 at 13:29
  • @Rohan, I will want to use `quantity` to compute the `total` later after setting the `price`, i.e. `e.total = quantity*price` – DannyClay Sep 09 '13 at 13:31

3 Answers3

4

You are looking for the strtod strtof library function (include <stdlib.h>). Relatedly, if the calling code uses anything other than strtoul to convert quantity from text to an int, that is probably a bug (the only exception I can think of would be, if for some reason quantity can be negative, then you would want strtol instead).

zwol
  • 135,547
  • 38
  • 252
  • 361
  • I accepted this answer because this addresses the main question above regarding "casting" a text/string to a float. Instead of `strod`, though, I used `strtof`. – DannyClay Sep 09 '13 at 13:51
  • 1
    This is not called "casting" in this context. This would be "parsing". – user7116 Sep 09 '13 at 14:01
  • I, uh, tend to forget `strtof` exists (because the analogous `strtoi` doesn't). You're quite right, though. – zwol Sep 10 '13 at 15:40
1

To convert text to a float, use strtof(). strtod() is better for double.
Your initialize routine likely wants a copy of the `date, etc.
A suggested improved routine follows:

expense_record initialize(const char * date, int quantity, const char *price, const char *item) {
  expense_record e;
  char *endptr;
  e.date = strdup(date);
  e.quantity = quantity;
  e.item = strdup(item);
  if (!e.date || !e.item) {
    ; // handle out-of -memory
  }
  e.price = strtof(price, &endptr); 
  if (*endptr) {
    ; // handle price syntax error
  }
  return e;
}

BTW: Recommend an additional change to pass into your initialization the destination record, but that gets into higher level architecture.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • although I limited my question to casting or converting a `char *`, the answer you posted provides a more thorough review of the code. Thank you for the additional insights. Why would you suggest a `copy` of the date and others? Also, I tried `e.total = e.quantity*e.price` but don't get the expected results (really big numbers). – DannyClay Sep 09 '13 at 14:01
  • One needs to see the code that calls `initialize` to properly address the need (or not) for the `strdup()`. I suspect your code will. – chux - Reinstate Monica Sep 09 '13 at 15:13
  • What value is a sample errant `e.total`, `e.quantity` and `e.price`? Maybe invalid `e.quantity` or missing prototype for `strtof()`. – chux - Reinstate Monica Sep 09 '13 at 15:15
0

You are having a segmentation fault because a float have 4 Bytes: when you make *(float *)price you are accesing to the first 4 Bytes of price, so if price´s size is smaller than 4 chars, you will have an error.

I think that the best you can do is read a float instead a char * when you parse the data (as i supose yo do with quantity), for example fscanf (pFile, "%s;%d;%f;%s", &date, &quantity, &price, &item);

or convert to float in initialize with strtod instead of make a cast.

Narkha
  • 1,197
  • 2
  • 12
  • 30
  • You can't count on a crash happening if "price's size is smaller than 4 chars"; contrariwise there are several reasons why it might crash even if there are `sizeof(float)` bytes of accessible memory at that address (misalignment, loading a signaling NaN with FPU exceptions enabled, ...); also, [`scanf` should never be used](http://stackoverflow.com/questions/17067147/how-to-remove-warnings-regarding-use-of-scanf-in-qt/17067360#17067360). – zwol Sep 10 '13 at 15:39
  • You have discovered me two new interesting topics about memory, thanks. But about scanf i do not agree: maybe is not the safest if you do not use taking the propers precautions, but since it is in the stdlib for me is valid. Besides, a query about qt is not the most appropriate argument when this question is about c. – Narkha Sep 10 '13 at 16:57
  • The C standard library is very old and contains many things that are, at least, poorly designed, at worst, catastrophically dangerous. Nobody would argue with the assertion that `gets` should never be used, ne? It is *just as impossible* to use `scanf` safely (thanks to the "input overflow causes undefined behavior" issue). That old answer of mine contains the clearest explanation of *why* `scanf` should never be used; I admit the advice for what to do instead is not helpful in *this* context, but there are plenty of obvious options (you mention one: `strtod`). – zwol Sep 10 '13 at 17:33
  • Ok, scanf is not safe to read strings (% s), which can produce an overflow of entry, but for all other data types i am not so sure, for example, since scanf used internally strtod for read floats, scanf("%f", &number) is as safe as calling strtod, and for more complex entries, scanf can give more funcinalidades scanf("%f;%f", &n1, &n2) – Narkha Sep 11 '13 at 17:41
  • No, in fact, `scanf("%f", &n);` *is not* safe. Input overflow causes undefined behavior. The C runtime is allowed to *crash* if the *user types too many digits*. This is not the case for `strtof`. – zwol Sep 11 '13 at 20:31