由于几乎所有旨在从stdin
获取数据的C函数都是不良/有缺陷的:
gets
对此说的越少越好
scanf
不检查缓冲区是否溢出,并且'\n'
始终保留在stdin
中,从而使接下来的scanf
s次出现
scanf_s
几乎相同,但是具有缓冲区溢出检查fgets
将'\n'
附加到string
gets_s
没有先前的问题,但对其他流没有用我决定编写自己的函数,该函数至少可用于从stdin
读取数字
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void *scano(char mode);
int main()
{
// int *num = (int *) scano(sData, 'd');
float *num = (float *)scano('f');
printf("Half: %f", *(num)/2);
return 0;
}
void *scano(char mode){
char sData[20];
fgets(sData, 20, stdin);
*(sData + strlen(sData) - 1) = '\0'; //get rid of the '\n' before the '\0'
switch(mode){
case 'd':{
int *dataI = (int *)malloc(sizeof(int));
*dataI = atoi(sData);
return dataI;
}
case 'f':{
float *dataF = (float *)malloc(sizeof(float));
*dataF = atof(sData);
return dataF;
}
case 'D':{
//double...
}
}
}
对于其他数据类型,该功能显然未完成,但是我首先要提出一些问题:
free()
中的case
吗?我知道分配的内存
需要释放,但是在使用列表时,free()
仅
用于删除Nodes
,在创建Nodes
时未调用任何free()
malloc()
之后。答案 0 :(得分:1)
下面是几个从输入源返回数字值的函数的简单示例。这些示例期望使用几种类型的空白字符(空格,制表符,行尾,返回)来分隔一组数字字段。
这些是演示一种方法,肯定还有改进的空间。
我建议您看看atoi vs atol vs strtol vs strtoul vs sscanf
中有关问题和答案的讨论 fgetc()
函数用于一次从输入源中提取一个字符,并测试是否应继续或停止读取输入源。通过使用fgetc()
函数,当使用了scano_l()
和scan_d()
这些函数时,我们可以允许其他函数继续从输入源读取。
我们还通过使用本地缓冲区并返回实际值作为malloc()
或free()
来消除对long
及其伴随的double
和内存管理的需求
例如,下面将使用C ++ main对这些进行简单测试(_tmain()
是因为我正在使用Microsoft Visual Studio 2005生成Windows控制台应用程序)。可以通过编译然后尝试几种不同的数据输入方案来进行测试,其中先输入一个整数,例如1234
,然后输入一个或多个空格字符(空格,制表符,换行),然后是浮点数数字,例如45.678
,后跟至少一个空格字符,再加上一些文本字符。
// scan_no.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <stdlib.h>
extern "C" {
long scano_l (FILE *pFile);
double scano_d (FILE *pFile);
};
int _tmain(int argc, _TCHAR* argv[])
{
// test by reading a few white space delimited numeric value and then a
// text string just to demonstrate how it works.
long l = scano_l (stdin);
double d = scano_d (stdin);
char testBuffer[256] = {0};
fgets (testBuffer, 255, stdin);
printf (" value is %ld\n", l);
printf (" value is %lf\n", d);
printf (" value is %s\n", testBuffer);
return 0;
}
在我的情况下位于另一个源文件csource.c中的函数是:
#include <stdio.h>
#include <stdlib.h>
// define the states for our Finite State Machine. It be a simple one with
// straight transitions from one state to the next.
enum StateFSM {StateBegin = 1, StateAccept = 2, StateEnd = 3};
static char *fetchValue (FILE *pFile, char *buffer, int nMaxLen)
{
int iBuffIndex = 0;
enum StateFSM iState = StateBegin;
do {
// until we reach an end state of our state machine or we reach end of file
// on our input source, lets fetch characters from the input source and decide
// what to do with the character until our end state is reached.
// end state is either white space trailing the desired characters or end of file.
int iInput = fgetc (pFile);
if (feof(pFile)) break;
switch (iInput) {
case ' ':
case '\t':
case '\n':
case '\r':
// eat up any leading whitespace
if (iState != StateAccept) break;
// we have found trailing white space so we are done.
iState = StateEnd;
break;
default:
if (iBuffIndex < nMaxLen) {
// as long as we are not at the max length lets get a character into
// the supplied buffer. if we are at max buffer length then we will
// just eat any remaining characters until we come to white space.
buffer[iBuffIndex++] = (iInput & 0x7f);
}
iState = StateAccept;
break;
}
} while (! (iState == StateEnd));
return buffer; // be a good citizen and return the pointer provided to us. allows chaining.
}
long scano_l (FILE *pFile)
{
char buffer[32] = {0};
long lValue = 0;
char *pTemp;
lValue = strtol (fetchValue(pFile, buffer, 31), &pTemp, 10); // max characters is 31 to ensure zero terminator.
return lValue;
}
double scano_d (FILE *pFile)
{
char buffer[32] = {0};
double dValue = 0.0;
char *pTemp;
dValue = strtod (fetchValue(pFile, buffer, 31), &pTemp); // max characters is 31 to ensure zero terminator.
return dValue;
}
和其他方便的功能将是读取一串字符的功能。以下函数从输入中读取字符,并将其添加到字符缓冲区,直到读取结束字符或读取最大字符数为止。
非空格空格字符(制表符,换行符,返回符)被视为文本指示符的结尾。现在,空格字符被认为是有效的文本字符,该字符已添加到根据输入构造的字符串中。会丢弃所有前导的非空格空格,并将文本字符串视为从第一个字符开始,该字符不是非空格空格字符。
char * scano_asz(FILE *pFile, char *buffer, int nMaxLen)
{
int iBuffIndex = 0;
enum StateFSM iState = StateBegin;
do {
// until we reach an end state of our state machine or we reach end of file
// on our input source, lets fetch characters from the input source and decide
// what to do with the character until our end state is reached.
// end state is either white space trailing the desired characters or end of file.
int iInput = fgetc(pFile);
if (feof(pFile)) break;
switch (iInput) {
case '\t':
case '\n':
case '\r':
// eat up any leading non-space whitespace. spaces embedded in the string are
// considered part of the string. delimiters include tab, new line, return.
if (iState != StateAccept) break;
// we have found trailing non-space white space so we are done.
iState = StateEnd;
break;
default:
if (iBuffIndex < nMaxLen) {
// as long as we are not at the max length lets get a character into
// the supplied buffer. allowable characters include the space character
// but not other white space characters such as tab, new line, return.
buffer[iBuffIndex++] = (iInput & 0x7f);
if (iBuffIndex >= nMaxLen) break; // once we reach max size then we will break and exit.
}
iState = StateAccept;
break;
}
} while (!(iState == StateEnd));
if (iBuffIndex < nMaxLen) buffer[iBuffIndex] = 0; // terminate the string if there is roome in the buffer.
return buffer;
}