尝试将类型 char 转换为类型 float,但出现分段错误
Trying to convert type char to type float, but gettng segmentation fault
我正在尝试完成一个练习,该练习应该有助于巩固我对指针和结构的了解,其中结构指针作为参数传递给函数。提供的解决方案使用 scanf
来获取用户输入并且工作得很好,但是由于此功能(方法?)被认为是不安全的,我正在尝试找到实现相同结果的替代方法。
问题是一个 float 类型的结构成员导致分段错误,我在其中使用 strtof()
将用户输入从 char
转换为 float
与 fgets()
结合。我之前看过一些我认为可能有用的字符串函数(atof()
和 atoi()
- 将此函数的 return 值转换为浮点数),但一直无法成功实现转换和那些。正如我提到的,我正在尝试使用 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),但我发现结果很难解释,如果不是不可能的话。我将不胜感激。
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);
这是一个问题:
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;
}
我正在尝试完成一个练习,该练习应该有助于巩固我对指针和结构的了解,其中结构指针作为参数传递给函数。提供的解决方案使用 scanf
来获取用户输入并且工作得很好,但是由于此功能(方法?)被认为是不安全的,我正在尝试找到实现相同结果的替代方法。
问题是一个 float 类型的结构成员导致分段错误,我在其中使用 strtof()
将用户输入从 char
转换为 float
与 fgets()
结合。我之前看过一些我认为可能有用的字符串函数(atof()
和 atoi()
- 将此函数的 return 值转换为浮点数),但一直无法成功实现转换和那些。正如我提到的,我正在尝试使用 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),但我发现结果很难解释,如果不是不可能的话。我将不胜感激。
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);
这是一个问题:
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;
}