在C语言中将char指针强制转换为float类型

3
我有一个包含以下数据的平面文件:
date;quantity;price;item

我希望创建一个数据记录,使用以下结构体:
typedef struct {
  char * date, * item;
  int quantity;
  float price, total;
} expense_record;

我创建了以下初始化方法:

我创建了以下初始化方法:

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;
}

我的问题是如何从 char *price 中设置价格为float(结构体所需的类型)。我尝试最接近的方法,即不会生成编译器错误的方法是:

 e.price = *(float *)price

但这会导致分段错误。
谢谢!

你将什么作为参数价格(price)传递给initialize - us2012
所以你有一个以人类可读格式表示的价格,并想将其转换为浮点数?在这种情况下,您必须解析它,就像这个问题中所示...类型转换不是为此目的而设计的... - ppeterka
你对 quantity 做什么? - Rohan
@us2012 @ppeterka66 是的,我有一个以人类可读格式表示的“价格”,例如10.50,它作为“char * price”传递给“initialize”方法。 - DannyClay
@Rohan,我想在设置“价格”后使用“数量”来计算“总价”,即“e.total = quantity*price”。 - DannyClay
3个回答

4
你正在寻找 strtod strtof 库函数(包含在<stdlib.h>中)。相关地,如果调用代码使用除strtoul之外的任何东西将quantity从文本转换为int,那可能是个错误(我能想到的唯一例外是,如果由于某种原因quantity可以是负数,则应使用strtol)。

我接受了这个答案,因为它回答了上面关于将文本/字符串转换为浮点数的主要问题。不过,我使用的是strtof而不是strod - DannyClay
1
在这个上下文中,这不被称为“转换(casting)”,而应该是“解析(parsing)”。 - user7116
我常常会忘记 strtof 的存在(因为类似的 strtoi 不存在)。但你说得对。 - zwol

1
要将文本转换为float,请使用strtof()。对于double,最好使用strtod()
您的初始化程序可能需要`date`等的副本.
下面是一个建议改进后的例程:
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;
}

顺便说一下:建议在初始化中传入目标记录的附加更改,但这涉及到更高级别的架构。


虽然我在问题中只限制了将char *转换或转换的范围,但您发布的答案提供了对代码的更全面的审查。感谢您提供额外的见解。为什么您建议复制日期和其他内容?此外,我尝试过e.total = e.quantity*e.price,但没有得到预期的结果(非常大的数字)。 - DannyClay
需要查看调用“initialize”的代码,才能正确解决对“strdup()”是否需要的问题。我怀疑你的代码会需要它。 - chux - Reinstate Monica
样本中的 e.totale.quantitye.price 的值是什么?也许是无效的 e.quantity 或缺少了 strtof() 的原型。 - chux - Reinstate Monica

0

你遇到了一个分段错误,因为一个 float 占据了 4 个字节: 当你使用 *(float *)price 时,你正在访问 price 的前 4 个字节,所以如果 price 的大小小于 4 个字符,你将会有一个错误。

我认为最好的方法是,在解析数据时读取一个 float 而不是一个 char *(我想你这样做了),例如 fscanf (pFile, "%s;%d;%f;%s", &date, &quantity, &price, &item);

或者在 initialize 中使用 strtod 将其转换为 float 而不是进行类型转换。


如果“价格的大小小于4个字符”,就不能指望崩溃发生;相反,即使在该地址有sizeof(float)字节的可访问内存(不对齐、启用FPU异常加载信令NaN等),也有几个原因可能会导致崩溃。此外,scanf永远不应该被使用 - zwol
你给我发现了两个关于内存的有趣话题,谢谢。但是关于scanf,我不同意:也许如果你不采取适当的预防措施,它可能不是最安全的,但对我来说,既然它在stdlib中,就是有效的。此外,在这个问题是关于c语言时,关于qt的查询并不是最合适的论据。 - Narkha
C标准库非常古老,包含许多设计至少很糟糕,最坏的情况下是灾难性危险的东西。毫无疑问,没有人会反对这样的说法:gets永远不应该被使用,对吧?使用scanf也同样不可能安全(由于“输入溢出导致未定义行为”问题)。我以前的那个答案中包含了关于为什么scanf永远不应该被使用的最清晰的解释;我承认在这种情况下提供替代建议并不是有帮助的,但有很多明显的选择(你提到了其中之一:strtod)。 - zwol
好的,scanf不安全地读取字符串(%s),这可能会导致输入溢出,但对于所有其他数据类型,我不太确定,例如,由于scanf在内部使用strtod来读取浮点数,scanf(“%f”,&number)与调用strtod一样安全,并且对于更复杂的输入,scanf可以提供更多的功能,例如scanf(“%f;%f”,&n1,&n2)。 - Narkha
不,实际上 scanf("%f", &n); 是不安全的。输入溢出会导致未定义的行为。如果用户输入太多数字,C运行时允许崩溃。而这种情况在 strtof 中并不会发生。 - zwol

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接