试图将 char 类型转换为 float 类型,但 gettng 分段错误
Posted
技术标签:
【中文标题】试图将 char 类型转换为 float 类型,但 gettng 分段错误【英文标题】:Trying to convert type char to type float, but gettng segmentation fault 【发布时间】:2021-06-10 02:18:23 【问题描述】:我正在尝试完成一个练习,该练习应该有助于巩固我对指针和结构的知识,其中结构指针作为参数传递给函数。提供的解决方案使用scanf
来获取用户输入并且效果很好,但是由于此功能(方法?)被认为是不安全的,我正在尝试寻找一种替代方法来实现相同的结果。
问题是一个浮点类型的结构成员导致了分段错误,我将strtof()
与fgets()
结合使用,将用户输入从char
转换为float
。我之前看过一些我认为可能有用的字符串函数(atof()
和atoi()
- 将此函数的返回值转换为浮点数),但无法成功地实现转换。正如我所提到的,我正在尝试使用strtof()
,但同样,我没有成功。
这是一个问题的例子:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
struct Stock
float cost;
;
#define SIZE 50
void ReadIn(struct Stock *purchase);
void PrintOut(struct Stock *receipt);
int main ()
// instantiate struct type
struct Stock product;
// instantiate struct type pointer
struct Stock *pItem;
pItem = &product;
if (pItem == NULL)
exit(-1);
else
ReadIn(pItem);
PrintOut(pItem);
return 0;
//---- Function Definitions ----//
// read function
void ReadIn(struct Stock *purchase)
char pNum[] = 0;
char *pEnd;
printf("\nEnter the price: ");
fgets(pNum, SIZE, stdin);
pEnd = (char *) malloc(SIZE * sizeof(char));
purchase->cost = strtof(pNum, &pEnd);
// print function
void PrintOut(struct Stock *receipt)
printf("\nPrice: %.2f\n", receipt->cost);
我知道我的实现中存在错误,但我不知道如何解决它们。我使用了各种调试技术(printf、IDE 内置调试器、lldb),但我发现即使不是不可能,也很难解释结果。我将不胜感激。
【问题讨论】:
你不需要为pEnd
分配内存。看看它是如何使用的here
使用标签来传达语言。
Den,有时作为文本的浮点值比 SIZE 50
字符多得多。 500个怎么样?
@Barmar 感谢您提供的示例,这些示例也参考了文档。我需要仔细研究一段时间才能更好地熟悉strtof()
。我对malloc
的使用是为了寻找无效内存访问问题的解决方案(以及对我尝试使用的工具的理解不足)的绝望尝试。
@Den 他的意思是你不需要把 [c] 放在问题标题中,因为它已经在标签中了。
【参考方案1】:
这是个问题:
char pNum[] = 0;
您已声明 pNum
仅存储一 (1) 个字符 - 它不能存储 SIZE
字符。每当您尝试读取它时,都会出现缓冲区溢出。您需要将其声明为
char pNum[SIZE+1] = 0; // +1 for the string terminator
其次,您不应该将任何内存分配给pEnd
- strtof
只会将其设置为指向pNum
中的第一个字符不 转换为float
.您应该检查 pEnd
以确保它是一个空白字符 - 这样您就知道用户输入了一个有效的浮点字符串。
以下是如何进行验证的示例:
void ReadIn(struct Stock *purchase)
char pNum[SIZE+1] = 0;
int done = 0;
float tmp;
do
printf("\nEnter the price: ");
if ( fgets(pNum, sizeof pNum, stdin) )
/**
* Do not update your target variable until after you've
* validated the input. pEnd will point to the first
* character in pNum that is *not* part of a valid floating
* point string.
*/
tmp = strtof( pNum, &pEnd );
/**
* isspace returns true/false - we'll assign the result to done
* to control our do/while loop. Basically, as long as the user
* does not enter a valid floating-point value, we'll continue the
* loop.
*/
if ( !(done = isspace( *pEnd )) )
/**
* If pEnd doesn't point to a whitespace character, then
* the input is invalid. Write an error message
* and get them to try again.
*/
fprintf( stderr, "%s is not a valid input - try again!\n", pNum );
/**
* If there's no newline in pNum, then the user entered
* a string that was too long for the buffer - read any
* remaining characters from the input stream until we see
* a newline.
*/
if ( !strchr( pNum, '\n' ) )
while ( getchar() != '\n' )
; // empty loop
else
/**
* There was a read error on the input stream - while there may be
* ways to recover, for the sake of this example we'll treat it
* as a fatal error and exit the program completely.
*/
fprintf( stderr, "Input error while reading stdin - bailing out...\n" );
exit(0);
while ( !done );
/**
* NOW we've made sure our input is valid, so we can assign it to the
* target variable.
*/
purchase->cost = tmp;
【讨论】:
"如果 pEnd 不指向空白字符,则输入无效。"。通常,当输入关闭或缓冲区刚刚填满时,有效的输入字符串可能以 null 字符 结尾。 OTOH"123 xsd"
将通过此代码。
@JohnBode:感谢您的验证实施。我正在考虑如何验证输入,但由于我在课程中还没有达到错误检查的地步,我可能会急于求成,不过,我很高兴能先睹为快这样的验证可能会消失。顺便说一句:你们的回复真的很快!
@JohnBode:我已经合并了你的代码,它运行良好,除了我按回车键,没有输入数字;程序运行到最后并退出。在按下回车后检查是否输入正确是我一直在调查的事情,但似乎无法通过isspace
以引入\r
。此外,还需要进行更深入的研究。【参考方案2】:
char pNum[] = 0;
将pNum
定义为具有单个 元素的数组。它只能是一个空字符串(仅包含空终止符)。尝试存储多个元素将超出范围并导致未定义的行为
如果您想在该数组中存储最多 SIZE - 1
个字符,则需要将其设为 SIZE
大:
char pNum[SIZE]; // Initialization is not needed, will be filled in by fgets
您还误解了strtof
的工作原理。您不应为作为第二个参数传递的指针分配内存。正在发生的事情是,它是一种通过传递指向变量的指针来模拟 按引用传递 的方法。
而且不管怎样,传递一个空指针是可以的:
purchase->cost = strtof(pNum, NULL);
【讨论】:
感谢您的观察。我按照建议更改了pNum
,它似乎已经解决了这个问题。至于'strtof';我正在查看各种排列以使程序运行,意识到'strtof(pNum,&pEnd)'是不正确的(在这种情况下,因为我在其他地方看到了该实现的示例);我已经按照您的示例实现了该函数(并且没有 malloc),但是由于我的代码的其他方面不正确,我无法确定我的“strtof”实现是否正确。以上是关于试图将 char 类型转换为 float 类型,但 gettng 分段错误的主要内容,如果未能解决你的问题,请参考以下文章
Arduino中数据类型转换 float/double转换为char 亲测好使,dtostrf()函数