以下是从输入源返回数值的几个函数的简单示例。这些示例期望使用几种类型的空白字符(空格、制表符、行尾、回车)中的一种来分隔一组数字字段。
这些是为了展示一种方法,肯定有改进的余地。
建议大家看看atoi vs atol vs strtol vs strtoul vs sscanf的问答讨论
fgetc() 函数用于从输入源一次拉出一个字符,并测试输入源的读取应该继续还是停止。通过使用fgetc() 函数,我们可以允许其他函数在使用scano_l() 和scan_d() 时继续从输入源读取数据。
我们还通过使用本地缓冲区并将实际值作为long 或double 返回,从而消除了对malloc() 和伴随的free() 和内存管理的需要。
例如,使用 C++ 主程序对这些进行简单测试(_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;
}